Mapa de espacios
Cada soporte georreferenciado, coloreado por su Score de Calidad del Espacio. El anillo punteado es el radio de influencia; una línea roja une soportes que se solapan y compiten por el mismo tránsito.
Inventario
Parque completo del cliente: medidas, proveedor, costo y eficiencia por metro cuadrado contra la mediana de la ciudad.
Clic en una fila para abrir la ficha, editar los datos del soporte y calificarlo. La columna vs mediana compara el costo por m² del espacio contra la mediana de su ciudad.
Evaluación mixta
El score combina cuatro señales cuantitativas y cinco cualitativas, con pesos que se ajustan por cliente. La matriz de decisión cruza calidad contra eficiencia de costo.
Pesos del modelo
Suman 100. Ajustá según lo que la marca esté comprando en esta campaña.
Matriz de decisión
Eje X: eficiencia de costo (mediana de la ciudad = 50). Eje Y: score de calidad. Área del punto: m².
Ranking del parque
Fotomontaje
Se marcan las cuatro esquinas del soporte en la foto y el arte se deforma en perspectiva sobre ellas. La proporción se bloquea contra las medidas reales del espacio, así el montaje no miente sobre el tamaño.
Después el arte, y arrastrá los cuatro vértices hasta las esquinas del soporte.
Malla de 24×24 celdas con homografía exacta: las líneas rectas del arte siguen siendo rectas en perspectiva.
Propuesta
Comparación del parque vigente contra la selección propuesta, con el saldo de inversión que queda por cubrir o liberar.
Selección propuesta
Movimiento de inversión
Contratos y vencimientos
Vigencia de cada unidad y aviso anticipado para decidir renovación o suspensión antes de que el contrato se renueve solo.
La decisión de gestión que se marca acá es la que después Abastecimiento comunica formalmente al proveedor. Los contratos OOH son bilaterales entre el anunciante y el arrendador: la agencia avisa, no firma.
Monitoreo en terreno
Verificación periódica de que cada soporte esté instalado, completo e iluminado. Lo que no se verifica no se puede reclamar.
Cumplimiento por ciclo
Los días fuera de aire se valorizan al costo diario del espacio (costo mensual ÷ 30) y arman el monto a reclamar al proveedor del ciclo.
Cómo se evalúa un espacio
Cuatro datos que salen del sistema y cinco notas que pone el planner. Todo se normaliza a una escala de 0 a 100, se pondera y se descuenta el solapamiento.
Los cuatro componentes automáticos
No se califican a mano: se calculan con los datos de la ficha.
Ejemplo completo, paso a paso
Rúbrica de las cinco notas cualitativas
Proveedores e integraciones
Concentración del parque por arrendador y diseño del conector con TDT Mediatech.
Conector TDT Mediatech
TDT Mediatech publica dos productos: METRICS Suite (agencias y anunciantes: audiencias, cobertura y frecuencia, targeting hiperlocal) y POST (media owners: ocupación de inventario y métricas unificadas). El conector consume el primero como fuente de audiencia y el segundo como fuente de disponibilidad.
updated_since + webhook de cambios. Upsert por tdt_id contra la tabla espacios; nunca se pisan los campos que editó la agencia.ProviderAdapter, de modo que un proveedor nuevo se suma implementando cinco métodos, sin tocar el resto de la aplicación.Mapeo de campos
Interfaz del adaptador
interface ProviderAdapter {
listSites(since?: Date): Promise<RawSite[]>
getAvailability(ids: string[], range): Promise<Slot[]>
getAudience(ids: string[], target): Promise<Audience[]>
getRateCard(ids: string[]): Promise<Rate[]>
getAssets(id: string): Promise<Asset[]>
}
Arquitectura
Especificación de la versión productiva. Este prototipo corre entero en el navegador; lo que sigue es cómo se lleva a una aplicación multi-cliente en producción.
Stack
| Capa | Elección | Por qué |
|---|---|---|
| Front | Next.js 15 (App Router) + TypeScript + Tailwind | SSR para las vistas pesadas de tabla, rutas API en el mismo repo, despliegue en Vercel sin infraestructura propia. |
| Mapas | Google Maps JS API + Places + Street View | Continuidad con los My Maps que ya usa el equipo, importación directa de KML y relevamiento remoto con Street View. |
| Datos | Postgres 16 + PostGIS (Supabase) | ST_DWithin resuelve solape y cobertura en la base; GIST sobre geog mantiene las consultas por radio en milisegundos. |
| Autenticación | Supabase Auth + RLS por tenant_id | Aislamiento real entre clientes: la política vive en la base, no en el código de la aplicación. |
| Archivos | Supabase Storage + transformaciones | Fotos originales, montajes y artes con miniaturas firmadas y expiración. |
| Imagen | Canvas en cliente para el montaje, sharp en servidor para el render final | El ajuste es interactivo; el render de alta resolución para el PDF se hace del lado del servidor. |
| Documentos | pdfmake o Puppeteer con plantilla HTML | Mismo layout en pantalla y en el entregable; plantilla por cliente con su identidad. |
| Trabajos | Supabase Cron + colas | Sincronización con proveedores, recálculo de scores y alertas de vencimiento de contrato. |
Modelo de datos
Multi-tenant por tenant_id en cada tabla, con RLS activada. El cliente final es advertiser y cuelga del tenant, de modo que una agencia ve todas sus cuentas y un usuario de marca ve sólo la suya.
tenant id, nombre, plan, identidad_visual
usuario id, tenant_id, rol (admin|planner|ejecutivo|lectura)
advertiser id, tenant_id, nombre, marcas[]
proveedor id, tenant_id, razon_social, contacto, nit, ssma_ok
espacio id, tenant_id, advertiser_id, proveedor_id, nombre, tipo,
geog geography(Point,4326), ancho_m, alto_m, m2 generated,
iluminado, caras, estado, tdt_id, external_ref
tarifa id, espacio_id, vigencia_desde, vigencia_hasta,
costo_neto, costo_bruto, moneda, produccion_incluida
disponibilidad id, espacio_id, desde, hasta, origen (tdt|proveedor|manual)
audiencia id, espacio_id, fecha_corte, ots_dia, alcance, frecuencia, fuente
evaluacion id, espacio_id, usuario_id, fecha, visibilidad, estado_soporte,
entorno, afinidad, riesgo, notas
score id, espacio_id, modelo_id, valor, componentes jsonb, calculado_en
modelo_score id, tenant_id, advertiser_id, pesos jsonb, vigente
foto id, espacio_id, tipo (relevamiento|montaje|instalado), url, tomada_en
campana id, tenant_id, advertiser_id, marca, nombre, desde, hasta
espacio_campana espacio_id, campana_id, desde, hasta (qué está al aire y cuándo)
contrato id, tenant_id, proveedor_id, referencia, desde, hasta, renovacion_automatica
espacio_contrato espacio_id, contrato_id, gestion (pendiente|renovar|suspender|renegociar)
poi id, tenant_id, ciudad, nombre, tipo, geog (centros comerciales, aeropuertos, ferias…)
propuesta id, tenant_id, advertiser_id, campana_id, nombre, periodo, estado, creada_por
propuesta_item propuesta_id, espacio_id, meses, costo_negociado, orden
auditoria id, tenant_id, usuario_id, entidad, accion, antes jsonb, despues jsonb
Consulta de solape
SELECT a.id, b.id, ST_Distance(a.geog, b.geog) AS metros FROM espacio a JOIN espacio b ON a.advertiser_id = b.advertiser_id AND a.id < b.id AND ST_DWithin(a.geog, b.geog, 400) WHERE a.estado = 'activo' AND b.estado = 'activo';
Score de Calidad del Espacio
Cada componente se normaliza a 0–100 y se pondera. El resultado se multiplica por un factor de canibalización que castiga tener dos soportes propios peleando por el mismo tránsito.
SCE = ( Σ wᵢ · vᵢ ) · factor_solape Cuantitativo impacto norm_log(OTS diario de la ubicación) peso 25 tamaño min(m² / 300, 1) · 100 peso 15 eficiencia clamp(mediana_ciudad / CPM_efectivo, 0, 2)·50 peso 12 exposición iluminado / digital / horas visibles peso 8 CPM_efectivo = costo bruto mensual / (OTS · 30 · share of voice / 1000) En una pantalla el share of voice reparte el costo entre los spots del loop, así un soporte digital y una valla se comparan en la misma unidad. Cualitativo (0–10 del planner, ×10) visibilidad ángulo, distancia de lectura, obstrucción peso 10 soporte estructura, lona, mantenimiento peso 8 entorno limpieza visual, saturación, seguridad peso 8 afinidad perfil de la zona contra el target peso 9 riesgo permisos, accesos, SSMA (10 = sin riesgo) peso 5 factor_solape = max(0.75, 1 − 0.10 · vecinos_mejores_en_400m)
Tramos: ≥ 70 indispensable · 50–69 buena · < 50 prescindible. Son los mismos tres tramos del semáforo que ya usa el equipo, ahora con un número detrás que se puede discutir con el cliente.
API
GET /api/espacios?ciudad&tipo&proveedor&bbox&score_min POST /api/espacios alta manual POST /api/espacios/import KML | KMZ | CSV | XLSX PATCH /api/espacios/:id POST /api/espacios/:id/evaluacion POST /api/espacios/:id/montaje multipart: foto, arte, quad[4] GET /api/scores?modelo=:id GET /api/alertas?dias=60 vencimientos de contrato GET /api/pois?ciudad&tipo&cerca_de=:espacio_id GET /api/campanas?advertiser&al_aire=true POST /api/propuestas crea y versiona POST /api/propuestas/:id/export pdf | pptx | xlsx POST /api/sync/tdt disparo manual de sincronización GET /api/proveedores/:id/disponibilidad
Roadmap
Sobre este prototipo
Corre sin servidor propio: los datos del parque de La Paz y Oruro salen de los dos reportes de Studio X, las coordenadas son aproximadas hasta importar los KML de los My Maps, y el mapa dibuja sus propias capas en Web Mercator porque el entorno del prototipo no carga tiles externos. Todo lo demás —score, solape, montaje, armado de propuesta y PDF— es funcional.