Terminal v3 (pricing de lanes de flete)
Producto de inteligencia de tarifas de flete por lane (hub origen → corredor destino). Un pipeline de SQL versionado por release materializa la tabla
terminal_v3.datarelease_<fecha>ensolvento-risk-analytics-proda partir de los modelos dbt de Syntage. Se construye a mano corriendo unmake.
Terminal arrastra historia y deprecaciones (leer antes de tocar)
Terminal pasó por muchas versiones con manejo de versiones/escala irregular, y quedó ruido de cosas deprecadas no señalizadas. Lo vigente y oficial es este repo (terminal). Está deprecado (no usar como referencia):
- El cálculo de terminal en dbt-etls (
models/terminal_client/,models/terminal_market/, tabla…terminal.client_dbt) — eliminado del repo el 2026-09-11. - El export a Supabase vía
Terminal_Uploader— apagado el 2026-09-11 (Supabase borrado, front de Lovable despublicado, scheduler eliminado). Ver Apagado Terminal → Supabase. - Versiones/repos viejos de "terminal" dispersos.
La vía de consumo viva es Metabase (corregido 2026-07-25)
El front de Terminal consume cards de Metabase a través de solvento-api. Los IDs efectivos por ambiente viven en flux/app-config (apps/<env>/solvento-api-values.yaml, variables DATA_ACCESS_QUESTION_ID_*), no en los defaults del repo solvento-api.
Hasta el 2026-07-25 esta ficha decía lo contrario (Metabase deprecado, Supabase vivo). Era incorrecto y mandó a diagnosticar por el camino equivocado. Los releases/*/metabase/ sí siguen siendo legado, pero eso es otra cosa: se refiere al despliegue documental del modelo, no al consumo.
¿Llegaste hasta acá desde…?
| Si ves… | Eso sale de… | La lógica está en… |
|---|---|---|
| Tarifa / precio por km / intervalos por lane | solvento-risk-analytics-prod.terminal_v3.datarelease_<fecha> |
repo terminal, releases/<fecha>/sql/ |
| Volumen estimado de una lane (corregido por rezago SAT) | terminal_v3.datarelease_<fecha> (columnas volume_estimated, …) |
releases/<fecha>/sql/02_…_volume_maturation.sql (modelo Weibull) |
| Tarifas de lanes en el front de la app | cards de Metabase del modelo del release, servidas por solvento-api |
IDs por ambiente en flux/app-config → apps/<env>/solvento-api-values.yaml |
| El front muestra datos viejos (un mes que ya debería haber pasado) | Puede ser la tabla o el ID de la card. Ver Si falla / está desactualizado | Primero verificar MAX(departure_month) en BQ; recién después mirar los question IDs |
terminal.client_dbt en dbt-etls |
Eliminado el 2026-09-11 | Ya no existe — ver Apagado Terminal → Supabase |
Resumen
| Campo | Valor |
|---|---|
| Qué es | Pricing de lanes de flete (hub → destino): tarifa promedio, precio/km, intervalos, volumen |
| Salida | solvento-risk-analytics-prod.terminal_v3.datarelease_<YYYYMMDD> (+ _customers, _volume_weekly/monthly) |
| Patrón | Pipeline de SQL versionado por release, corrido a mano (make) — no hay scheduler que lo construya |
| Lee de | dbt-analytics (analytics_engineering_core.fact_syntage_invoices*, _intermediate.int_carta_porte), analiticas.precios_diesel, syntage.distancias_municipios |
Grano de datarelease |
una fila por (departure_month, hub_origin, destination) |
| Criticidad | 🟡 Media (producto analítico; build manual) |
| Consumo | Front de la app vía solvento-api → cards de Metabase. IDs por ambiente en flux/app-config |
| Autor/dueño | Angel Gutierrez · coordinación de datos: Martin |
| Repo | terminal · config de consumo: flux/app-config |
Diagrama de linaje
graph LR
RAW[("solvento-data-prod.syntage<br/>invoices · cp_* · distancias_municipios")]
DSL[("analiticas.precios_diesel<br/><i>diesel/banxico scrapers</i>")]
subgraph an["dbt-analytics · solvento-risk-analytics-prod"]
INT["analytics_engineering_intermediate<br/>int_carta_porte"]
CORE["analytics_engineering_core<br/>fact_syntage_invoices(_items)"]
end
subgraph term["repo terminal · make <fecha> (manual)"]
S0["00_release · approved_lanes + datarelease"]
S1["01_..._customers · variante clientes"]
S2["02_..._volume_maturation · Weibull"]
end
OUT[("solvento-risk-analytics-prod<br/>terminal_v3.datarelease_<fecha>")]
subgraph cons["consumo · vía viva"]
MB["Cards de Metabase<br/>modelo del release"]
API["solvento-api<br/>DATA_ACCESS_QUESTION_ID_*"]
FRONT["Front de Terminal"]
end
CFG["flux/app-config<br/>apps/<env>/solvento-api-values.yaml"]
DEP["❌ dbt-etls terminal_client<br/>❌ Supabase vía Terminal_Uploader<br/>APAGADO 2026-09-11"]
RAW --> INT --> S0
RAW --> CORE --> S0
DSL --> S0
S0 --> S1
S0 --> S2 --> OUT
OUT --> MB --> API --> FRONT
CFG -.->|define el ID por ambiente| API
OUT -.->|ya no| DEP
classDef store fill:#bfdbfe,stroke:#1e40af,color:#000;
classDef logic fill:#dcfce7,stroke:#15803d,color:#000;
classDef dep fill:#fee2e2,stroke:#b91c1c,color:#000;
class RAW,DSL,OUT store;
class INT,CORE,S0,S1,S2 logic;
class DEP dep;
Modelo de versiones (releases)
Cada versión es una carpeta releases/<YYYYMMDD>/:
releases/<YYYYMMDD>/
├── RELEASE_NOTES.md ← changelog, lanes agregadas/desactivadas, issues conocidos
├── sql/ ← definiciones de tablas/vistas BigQuery (el pipeline)
├── analysis/ ← notebooks Jupyter
└── metabase/ ← documentación de modelo (LEGADO — es el despliegue documental
lo deprecado; el CONSUMO por Metabase está vivo)
Los SQL canónicos de un release siguen el orden:
00_release_<fecha>.sql→approved_lanes_<fecha>(universo de cartas porte clasificadas en lanes) y la tabla principaldatarelease_<fecha>.01_release_<fecha>_customers.sql→ variante para clientes (datarelease_<fecha>_customers), usada por el análisis lane consistency clients vs market.02_release_<fecha>_volume_maturation.sql→ modelo Weibull que estima el volumen real corrigiendo el rezago de archivo del SAT, y re-escribedatarelease_<fecha>con columnasvolume_estimated,month_maturity_pct, etc.
Releases presentes hoy: 20260410, 20260421, 20260507, 20260515, 20260624. ⚠️ El README solo lista 20260410 (está desactualizado — parte del ruido).
Refrescar los datos SIN lanzar un release nuevo (lo más común) ⭐
Si no hay cambio de lógica, no hace falta crear un release nuevo: se re-corre el mismo. Verificado el 2026-07-25.
Por qué funciona:
- Los 9 statements de los 3 SQL son
create or replace table→ idempotentes, mismos nombres de tabla. - El corte de datos es 100% dinámico:
cutoff_logiccalculalast_visible_monthdesdeCURRENT_DATE('America/Mexico_City'). No hay fechas hardcodeadas (la única, en el00, está comentada). - Como los nombres de tabla no cambian, nada aguas abajo se toca: las cards de Metabase y los question IDs de
app-configsiguen funcionando. Cero re-deploy.
cd terminal
# 1. respaldo gratis del estado actual (CLONE no copia bytes)
bq query --use_legacy_sql=false \
"CREATE TABLE \`solvento-risk-analytics-prod.tmp.datarelease_<fecha>_bkp_<hoy>\`
CLONE \`solvento-risk-analytics-prod.terminal_v3.datarelease_<fecha>\`"
# 2. probar en sandbox y validar MAX(departure_month)
make <fecha>-core DATASET=tmp
# 3. publicar
make <fecha>-core DATASET=terminal_v3
El sufijo de fecha deja de significar 'fecha de los datos'
Al re-correr, datarelease_20260624 pasa a contener datos más nuevos que su nombre. Tratá el sufijo como versión del modelo, no como fecha de carga, y dejá constancia en el RELEASE_NOTES del release re-corrido. Si esto se automatiza, conviene exponer una vista estable (datarelease_current) y apuntar el consumo ahí.
Cuándo sí hace falta un release nuevo: cuando cambia la lógica (SQL, taxonomía de lanes, calibración de consistencia). Solo por refrescar datos, no.
Cómo lanzar una nueva versión
- Crear la carpeta
releases/<NUEVA_FECHA>/con susql/(lo más simple: copiar el último release y renombrar los 3 SQL al nuevo sufijo, ajustando la fecha de corte de datos). AgregarRELEASE_NOTES.md. - Los SQL usan el placeholder
{{BQ_DATASET}}en los nombres calificados (solvento-risk-analytics-prod.{{BQ_DATASET}}.tabla).scripts/run_sql.pylo reemplaza; solo se permitetmpoterminal_v3. - Probar en sandbox (
tmp) antes de publicar: - Publicar a producción (dataset
terminal_v3): - Actualizar
RELEASE_NOTES.mdy la tabla de releases del README. (El análisis opcional lane consistency se corre aparte:make <fecha>-lane-consistency-sql.)
Es un proceso manual y local (corre el
makequien publica el release). No hay Cloud Scheduler ni CI que construya las tablas; el CI del repo solo hace lint conruff.
Tablas que produce (por release)
| Tabla | Generada por | Grano |
|---|---|---|
terminal_v3.approved_lanes_<fecha> |
00_release STEP 1 |
fila por uuid (cartas porte clasificadas) |
terminal_v3.datarelease_<fecha> |
00_release STEP 2, re-escrita por 02_…_volume_maturation |
(departure_month, hub_origin, destination) |
terminal_v3.datarelease_<fecha>_customers |
01_…_customers |
variante clientes |
terminal_v3.datarelease_<fecha>_volume_weekly / _monthly |
02_…_volume_maturation |
volumen por ISO-week / mes |
Columnas clave de datarelease: avg_price (AVG subtotal_mxn, vigintiles 4–17), price_km (ppk), low/high_interval, avg_distance, volume_observed/estimated. Ver docs/data_dictionary.md y docs/lane_taxonomy.md en el repo.
Consumo
La vía viva es Metabase. El front de Terminal pide los datos a solvento-api, que ejecuta cards de Metabase (POST /api/card/{id}/query/json) y devuelve el JSON. Las cards leen terminal_v3.datarelease_<fecha>.
Los IDs efectivos son por ambiente y viven en flux/app-config, no en los defaults del repo solvento-api:
Estado al 2026-07-25 (verificado contra el repo y ejecutando las cards):
| Ambiente | ORIGINS / DESTINATIONS / DATA / BORDER_DOMESTIC / ROUTES | Modelo de card | Release que lee |
|---|---|---|---|
| demo / prod / staging | 6266 / 6265 / 6264 / 6267 / 6268 |
modelo 7 | datarelease_20260624 ✅ |
| development | 6006 / 6007 / 6008 / 6009 / 6010 |
modelo 6 | datarelease_20260515 ⚠️ desalineado |
- Editar el SQL de una card NO requiere re-deploy del backend: el ID se resuelve en cada request. Lo que sí rompe sin deploy de por medio es cambiar nombres de columnas de salida o template-tags — el
processResulty elschemadesolvento-apidependen de ellos. Cambiar el ID sí exige tocarapp-config(rollout de pods). - ⚠️
ORIGINS/DESTINATIONS/QUOTING(5494-5496) siguen sobre Terminal v2 (model_analytics_terminal_v2.v_quoting_*) en los cuatro ambientes. El quoting del front nunca migró a v3. - ⚠️ Los defaults del repo
solvento-api(5692-5694,5904,5909) están colgados de releases viejos:#5901→ release20260421y#5696→tmp.chr_20260302. Hoy todos los ambientes los sobreescriben por env, pero un ambiente nuevo sin override serviría datos de marzo. - Los
releases/*/metabase/son documentación legado del modelo. Eso no contradice lo anterior: el consumo por Metabase está vivo, lo que ya no se hace es ese despliegue documental.
Detalle completo en Consumo desde la app (Metabase).
Si falla / está desactualizado 🛠️
Impacto: los datos de Terminal quedan en la última versión publicada hasta que alguien re-corra el pipeline. No hay automatización que lo refresque.
"El front muestra un mes viejo" — diagnóstico en orden
No asumas que hay que lanzar un release. Recorré esto de arriba hacia abajo:
- ¿Qué mes tiene la tabla? Recordá el rezago por diseño: un mes M recién entra el día 15 de M+1. Si hoy es 10 de agosto, que el último mes sea junio es correcto, no un bug.
- ¿Está vieja la tabla? → re-corré el release en sitio (sección ⭐ de arriba). No hace falta release nuevo si no cambia la lógica.
- ¿La tabla está al día pero el front no? → mirá el question ID del ambiente en
flux/app-config(apps/<env>/solvento-api-values.yaml) y ejecutá esa card en Metabase. Si la card devuelve el mes correcto y el front no, es caché de navegador/CDN o caché de resultado de Metabase. - ¿Recién corriste el pipeline? → confirmá la hora de escritura antes de pedirle a alguien que recargue:
| Síntoma | Dónde mirar | Acción |
|---|---|---|
| Tabla con datos viejos | último datarelease_<fecha> y su MAX(departure_month) |
Re-correr el release en sitio (⭐). Release nuevo solo si cambia la lógica |
| Tabla al día, front viejo | question ID del ambiente en flux/app-config |
Alinear el ID al modelo del release vigente |
| Un ambiente distinto a los demás | comparar los DATA_ACCESS_QUESTION_ID_* entre apps/*/ |
Igualar (hoy development está atrasado) |
Falla make <fecha> |
Salida de scripts/run_sql.py; ¿.env con GCP_PROJECT? |
Probar primero en DATASET=tmp; revisar el SQL del step que falló |
| Faltan datos aguas arriba | Modelos dbt-analytics (int_carta_porte, fact_syntage_invoices*) |
Ver la capa dbt y el run de dbt Cloud |
Confusión con terminal_client (dbt-etls) |
Camino apagado el 2026-09-11 | Ya no existe; el cálculo vivo es este repo — ver Apagado Terminal → Supabase |
Escalación: lógica del modelo / releases → Angel Gutierrez (autor) · datos aguas arriba (dbt) → Diego · question IDs / deploy por ambiente → equipo de backend vía flux/app-config · resto → Martin.
Enlaces
- 📦 Repo:
terminal—releases/<fecha>/,Makefile,scripts/run_sql.py,docs/ - ⚙️ Config de consumo por ambiente:
flux/app-config→apps/<env>/solvento-api-values.yaml - 🔌 Cómo pega la app: Consumo desde la app (Metabase)
- 🧮 Aguas arriba: Capa dbt (
solvento-risk-analytics-prod)
Última actualización: 2026-07-25 · Corrección importante: hasta esta fecha la ficha decía que Metabase estaba deprecado y que el consumo iba por Supabase (Terminal_Uploader). Es al revés: el backend pega directo a Metabase y los question IDs por ambiente viven en flux/app-config. También se documentó que refrescar datos NO requiere un release nuevo: el pipeline es idempotente y el cutoff es dinámico.