Hush · Reescribe las reglas del campo de batalla

Cada bus, cada cupo, cada puesto en el mapa.

Disponibilidadde parqueaderos

21 terminales en Cundinamarca. Cupos libres, buses parqueados y próximas salidas en un mapa dinámico.

Puestos y horariospor bus

Registre llegadas y salidas, controle la permanencia y venda puestos antes de que el bus salga.

La solución
01 El reto

Tres preguntas,un mapa.

Una empresa de transporte intermunicipal necesita un sistema de software para gestionar sus buses y parqueaderos dentro de los límites de Cundinamarca, Colombia. Diseñamos un sistema de información geográfica sobre PostGIS y el mapa dinámico de OpenStreetMap, documentado con el modelo de vistas arquitectónicas 4+1, y lo entregamos como sistema web y como app móvil en Cordova.

a

Disponibilidad de cupos

“¿Cuántos cupos libres hay ahora en cada terminal?”

Cada llegada abre un parking_stay; cada salida lo cierra. v_parking_availability compara las estadías abiertas con la capacidad máxima de cada parqueadero, y un trigger bloquea el parqueadero para que nunca se sobrepase.

b

Ubicación de buses

“¿Dónde está el bus CB-127?”

No se necesita GPS: el bus se ubica en el parqueadero de su estadía abierta. Mientras un viaje está en ruta, PostGIS estima su posición sobre el trayecto con ST_LineInterpolatePoint según el tiempo transcurrido.

c

Puestos por bus

“¿Quedan puestos en el de las 13:05 a Ubaté?”

Cada ticket guarda un número de puesto de un viaje. Puestos disponibles = capacidad del bus − tiquetes vendidos. La base de datos rechaza puestos duplicados, puestos inexistentes y ventas después de la salida.

#RequisitoCómo se resuelveDónde
R1SIG con PostGIS + OpenStreetMapSupabase (PostgreSQL 17 + PostGIS) con geometrías SRID 4326; Leaflet dibuja los mosaicos de OSM.database/ · app/
R2Modelo de vistas 4+1Vistas de escenarios, lógica, de procesos, de desarrollo y física, con diagramas.§03 · docs/ARCHITECTURE.md
R3Diseño de la base de datos9 tablas, 6 vistas, índices espaciales GiST, triggers y funciones RPC.§04 · 01–06 *.sql
R4Solo dentro de CundinamarcaPolígonos del departamento + Bogotá D.C. desde OSM; un trigger con ST_Covers rechaza cualquier parqueadero por fuera.02_functions.sql
R5Ubicación del bus por parqueaderoparking_stay abierta → ubicación; no requiere rastreo en tiempo real.v_bus_location
R6Datos del bus: origen, destino, horas, permanenciatrip guarda origen, destino, hora de salida, hora de llegada y tiempo de permanencia en el parqueadero.Registrar → Nuevo viaje
R7El administrador registra llegadas y salidasapi_register_arrival / api_register_departure, solo para su propio parqueadero.Pestaña Registrar
R8Mapa: ubicación, cupos, salidas, horarios de conductoresAnillos de ocupación, buses parqueados con su próxima salida y turnos de servicio de conductores por terminal.Terminales · Conductores
R9App móvil con CordovaEl mismo código empaquetado con Cordova + plugin de geolocalización.§06 · mobile/
R10GeocodificaciónGeocodificación directa/inversa con Nominatim + KNN de PostGIS para la “terminal más cercana”.api_nearest_lots
02 La red

21 terminales.Una frontera.

Los parqueaderos de la empresa, exactamente como aparecen en el taller, sobre OpenStreetMap. Todo lo que está fuera de Cundinamarca y Bogotá D.C. se oscurece: la propia base de datos se niega a registrar una terminal más allá de esa línea.

Área de servicio · relaciones OSM 1305533 + 12893646
0
Parqueaderos
0
Cupos en total
0
El mayor · Bogotá D.C.
0km
Mayor distancia en línea recta
MunicipioCapacidad
03 Arquitectura

El modelode vistas 4+1.

El modelo de Kruchten describe el sistema desde el punto de vista de cada interesado. Cuatro vistas — lógica, de procesos, de desarrollo y física — se integran y validan con una quinta: los escenarios (casos de uso).

Escenarios

Interesados · todos — valida las otras cuatro vistas

Casos de uso derivados del taller. Cada uno se rastrea en las demás vistas: p. ej. Registrar llegada se vuelve la clase ParkingStay (lógica), la secuencia de llegada (procesos), api_register_arrival (desarrollo) y una llamada del celular a Supabase (física).

  • Administrador del parqueadero registra llegadas, salidas e información de viajes de su terminal.
  • Despachador sigue la disponibilidad, los buses en ruta y los horarios de conductores.
  • Pasajero / taquillero encuentra la terminal más cercana y consulta o vende puestos.
  • Administrador del sistema gestiona terminales, siempre dentro de Cundinamarca.
Hush Admin. parqueadero Despachador Pasajero · taquilla Admin. del sistema «incluye» Registrar llegada del bus Registrar salida del bus Registrar datos del viaje Consultar cupos disponibles Ubicar buses en el mapa Horarios de conductores Consultar y vender puestos Terminal más cercana (geocodificación · Nominatim + KNN) Gestionar parqueaderos Validar límites de Cundinamarca

Vista lógica

Interesados · usuarios finales, analistas — funcionalidad

El modelo de dominio. Los objetos espaciales (ServiceArea, ParkingLot) llevan geometrías PostGIS; toda la operación cuelga del Trip (la “información del bus”) y del ParkingStay (lo que registra el administrador).

  • ParkingStay = una llegada + una salida → el tiempo real de permanencia.
  • Trip = origen, destino, salida, llegada y permanencia planeada.
  • Ticket = un puesto de un viaje → disponibilidad de puestos.
  • DriverShift = horario de servicio del conductor, con base en una terminal.
cubre 1* 1* 1* 1* *1 origen · destino2* *1 1* *1 terminal base 1*administra ServiceAreanamegeom : MultiPolygon ParkingLotcode, municipalitynamecapacity : 1..50geom : Point (4326) AppUserusername, full_namerole : LOT_ADMIN | SYSTEM_ADMIN Busplate : ABC123internal_code, brandseat_capacity : 10..60 ParkingStayarrived_atdeparted_at [0..1]/ dwell_time DriverShiftstarts_atends_at (≤ 12 h) Ticketseat_numberpassenger_name Triporigen → destinoscheduled_departurescheduled_arrivaldwell_minutessalida / llegada realstatus Driverfull_name, document_idlicense : C1 | C2 | C3

Vista de procesos

Interesados · integradores — concurrencia, desempeño

Comportamiento en ejecución del escenario más crítico: registrar la llegada de un bus. Toda la operación es una única transacción de PostgreSQL ejecutada por una función RPC.

  • Concurrencia: el trigger de capacidad bloquea la fila de parking_lot (FOR UPDATE), así dos administradores no pueden ocupar el último cupo al mismo tiempo.
  • Los errores se lanzan en SQL y regresan como mensajes legibles.
  • El mapa consulta api_overview() cada 30 s — una sola petición trae parqueaderos, buses y estadísticas.
  • Los buses en ruta se reinterpolan en el cliente cada 15 s.
Admin. parqueaderocelular / navegador App Hushapp.js · api.js Supabase PostgRESTHTTPS · JSON api_register_arrivalSECURITY DEFINER PostgreSQL+ PostGIS · triggers 1 · bus, parqueadero, hora 2 · POST /rpc/api_register_arrival 3 · llamada (una transacción) 4 · valida admin · cierra viaje 5 · INSERT parking_stay 6 · trigger: bloquea FOR UPDATE ¿ocupados < capacidad? si no, RAISE 7 · stay_id | “parqueadero lleno” 8 · resultado JSON / error 9 · 200 OK | 400 + mensaje 10 · aviso + refresca el mapa

Vista de desarrollo

Interesados · programadores — organización del código

Capas y los archivos que las implementan. Las reglas de negocio viven en la base de datos, así el sistema web, la app Cordova y cualquier cliente futuro obedecen exactamente las mismas reglas.

  • app/ se comparte tal cual entre la web y la app móvil (npm run sync).
  • api.js es el único módulo que habla con la red.
  • El SQL se versiona en orden: esquema → reglas → vistas → datos → API.
PresentaciónHTML · CSS Página de inicioindex.html Sistema webapp/index.html · app.css App Cordovamobile/www + geolocation Lógica clienteJavaScript app.jsestado · paneles · formularios Leaflet 1.9mosaicos OpenStreetMap api.jssupabase-js · Nominatim APISupabase PostgREST/rest/v1 · /rpc Políticas RLSsolo lectura para clientes funciones api_*06_api.sql ReglasPL/pgSQL fn_register_arrival / departure02_functions.sql Triggerslímites · capacidad · traslapes · puestos DatosPostgreSQL 17 Tablas01_schema.sql Vistas03_views.sql PostGISgeometry · GiST Datos semilla04 · 05 *.sql

Vista física

Interesados · ingenieros de sistemas — despliegue, topología

Dónde corre cada pieza. Los clientes son livianos: dibujan el mapa OSM y llaman a la API de Supabase por HTTPS. El único servidor es el proyecto administrado de Supabase, desplegado en la región us-east-1 (Virginia, EE. UU.).

  • Celulares: WebView de Cordova + GPS del dispositivo (plugin de geolocalización).
  • Supabase: API PostgREST delante de PostgreSQL 17 + PostGIS 3.
  • OpenStreetMap: mosaicos raster y geocodificación con Nominatim.
  • Sin servidor de aplicaciones que mantener.
HTTPS · JSON HTTPS · mosaicos PNG HTTPS · geocodificación (directa / inversa) HTTPS · JS / CSS / fonts CelularAndroid / iOSCordova WebView · app/GPS · geolocation plugin Estación de trabajoChrome · Edge · FirefoxSistema web · app/Inicio · index.html Nube Supabaseregión us-east-1 · VirginiaPostgREST API · RLSPostgreSQL 17PostGIS 3 · plpgsql OpenStreetMaptile.openstreetmap.orgmosaicos raster · ODbL Nominatimnominatim.openstreetmap.orgAPI de geocodificación CDNsunpkg · jsDelivrGoogle Fonts
04 Base de datos

PostGIS haceel trabajo.

Nueve tablas en PostgreSQL + PostGIS (SRID 4326). Las reglas del negocio se imponen dentro de la base de datos — triggers, restricciones y funciones — para que ningún cliente pueda meter un bus en una terminal llena ni crear una terminal fuera de Cundinamarca.

service_area límites

  • idPKserial
  • nameUQvarchar(80)
  • geomGISMultiPolygon 4326

parking_lot terminales

  • idPKserial
  • codeUQvarchar(4)
  • municipalityUQvarchar(60)
  • namevarchar(120)
  • capacitysmallint 1..50
  • geomGISPoint 4326 · GiST

bus flota

  • idPKserial
  • plateUQ^[A-Z]{3}[0-9]{3}$
  • internal_codeUQvarchar(10)
  • brand · model_yearvarchar · smallint
  • seat_capacitysmallint 10..60
  • activeboolean

trip información del bus

  • idPKserial
  • bus_idFK→ bus
  • driver_idFK→ driver
  • origin_lot_idFK→ parking_lot
  • destination_lot_idFK→ parking_lot
  • scheduled_departuretimestamptz
  • scheduled_arrivaltimestamptz
  • dwell_minutessmallint
  • actual_departure · arrivaltimestamptz
  • statusSCHEDULED…ARRIVED

parking_stay llegadas · salidas

  • idPKserial
  • bus_idFK→ bus
  • parking_lot_idFK→ parking_lot
  • arrival_trip_idFK→ trip
  • departure_trip_idFK→ trip
  • arrived_attimestamptz
  • departed_attimestamptz NULL
  • *_registered_byFK→ app_user

ticket puestos

  • idPKserial
  • trip_idFK→ trip
  • seat_numberUQ (trip, seat)
  • passenger_namevarchar(120)
  • sold_attimestamptz

driver conductores

  • idPKserial
  • document_idUQvarchar(20)
  • full_name · phonevarchar
  • license_categoryC1 · C2 · C3

driver_shift horarios

  • idPKserial
  • driver_idFK→ driver
  • base_lot_idFK→ parking_lot
  • starts_at · ends_at≤ 12 h, sin traslapes

app_user administradores

  • idPKserial
  • usernameUQvarchar(40)
  • roleLOT_ADMIN · SYSTEM_ADMIN
  • parking_lot_idFK→ parking_lot
Solo dentro de Cundinamarca

Cada terminal se valida contra los polígonos del departamento importados de OpenStreetMap.

CREATE FUNCTION fn_in_service_area(p geometry) RETURNS boolean AS $$
  SELECT EXISTS (SELECT 1 FROM service_area sa
                 WHERE ST_Covers(sa.geom, p));
$$;
-- BEFORE INSERT OR UPDATE OF geom ON parking_lot
-- → RAISE 'La ubicación está fuera de Cundinamarca'
Nunca sobre la capacidad

La fila del parqueadero se bloquea antes de contar, así las llegadas concurrentes se serializan.

SELECT capacity INTO v_capacity FROM parking_lot
 WHERE id = NEW.parking_lot_id FOR UPDATE;
SELECT count(*) INTO v_occupied FROM parking_stay
 WHERE parking_lot_id = NEW.parking_lot_id
   AND departed_at IS NULL;
IF v_occupied >= v_capacity THEN RAISE EXCEPTION 'El parqueadero % está lleno'…
Terminal más cercana (KNN)

Dirección geocodificada → terminales más cercanas usando el índice GiST y el operador de distancia <->.

SELECT code, municipality, available,
       ST_DistanceSphere(pl.geom, q.g) / 1000 AS km
  FROM parking_lot pl JOIN v_parking_availability USING (id)
 ORDER BY pl.geom <-> ST_SetSRID(ST_MakePoint(lng, lat), 4326)
 LIMIT 3;
Posición estimada en ruta

No se requiere rastreo en tiempo real; mientras está en ruta, el bus se ubica sobre su trayecto según el tiempo transcurrido.

ST_LineInterpolatePoint(
  ST_MakeLine(origin.geom, destination.geom),
  LEAST(1, GREATEST(0,
    extract(epoch FROM now() - t.actual_departure) /
    extract(epoch FROM t.scheduled_arrival - t.scheduled_departure))))
05 El sistema

En vivo, sobreOpenStreetMap.

Este es el sistema de información real funcionando contra la base de datos en Supabase — no es una maqueta. Abra una terminal, registre una salida, venda un puesto o busque una dirección: cada acción pasa por las reglas de PostGIS de arriba.

hush · centro de controlPantalla completa

Terminales

Cupos libres, buses parqueados, permanencia, próximas salidas, llegadas y turnos de conductores por terminal.

En vivo

Un bus 3D recorre la vía real (OSRM) según la hora; síguelo con la cámara o acelera el reloj ×30 a ×600.

Registrar

Llegadas, salidas y nuevos viajes con origen, destino, horas y permanencia.

Puestos

Mapa de puestos por bus y viaje; venda un puesto y vea cómo se actualiza la disponibilidad.

06 App móvil

En el bolsillode cada admin.

La app móvil está hecha con Apache Cordova. Empaqueta exactamente el mismo código del sistema web, cambia a un panel inferior deslizable en pantallas pequeñas y usa el GPS del dispositivo para encontrar la terminal más cercana.

  1. Mismo código. npm run sync copia app/ en mobile/www e inyecta cordova.js.
  2. GPS nativo. cordova-plugin-geolocation alimenta la consulta KNN de “terminal más cercana”.
  3. Hecha para el patio. Botones grandes, navegación inferior a una mano, funciona en Android 7+.
mobile/
$ npm install
$ npm run sync              # app/ → www/
$ npx cordova platform add android
$ npx cordova run android   # o: npm run browser
07 Ejecutar

Cuatro pasosa la carretera.

Sin servidor de aplicaciones: la base de datos es un proyecto de Supabase y los clientes son archivos estáticos.

01

Base de datos

Cree un proyecto en Supabase y ejecute database/01…06_*.sql en orden (editor SQL o migraciones).

02

Conectar

Pegue la URL del proyecto y la llave pública en app/js/config.js.

03

Servir

Sirva la carpeta (p. ej. npx serve .) y abra esta página o app/.

04

Móvil

En mobile/: npm install, npm run sync, cordova run android.

Taller2/ ├── index.html esta página de inicio ├── app/ sistema de información web (Leaflet + supabase-js) ├── mobile/ proyecto Cordova (config.xml, script de sincronización) ├── database/ 01 esquema · 02 reglas · 03 vistas · 04 límites · 05 datos · 06 API ├── docs/ARCHITECTURE.md las vistas 4+1 por escrito └── assets/ video del hero, datos de la red