Tu inventario paradoes el inventario que otro dealer busca
La red donde los concesionarios cambian inventario entre sí, con el diferencial en dólares calculado antes de sentarse a negociar
Plataforma SaaS B2B · Web app para concesionarios
Desarrollo frontend y capa de integración con la API
Build de producción generado y apuntando a la API pública del backend; acceso restringido a concesionarios registrados
Toyota Corolla LE
68.400 km
Ford Ranger XLT
91.200 km
Dos concesionarios con el vehículo del otro y ninguna forma de saberlo
El cambio ocurría por WhatsApp
Un concesionario con un sedán parado 90 días en piso y un cliente que quiere una pickup no tiene forma sistemática de saber qué otro dealer de la red tiene exactamente esa pickup y aceptaría su sedán a cambio. El intercambio entre concesionarios existe, pero ocurre por WhatsApp, por conocidos y a ciegas: nadie sabe cuánto dinero hay que encimar hasta que ya se perdió la tarde comparando precios a mano, y las negociaciones se pisan porque ambas partes responden al mismo tiempo sin saber a quién le toca el turno.
Publicar una vez y dejar que la red cruce
Publicar cada unidad una sola vez, con sus criterios de intercambio explícitos, y dejar que el motor de matching haga el cruce contra toda la red. La interfaz presenta cada oportunidad como un intercambio de dos lados —lo que entregas frente a lo que recibes— con el diferencial neto calculado, la comisión de plataforma desglosada y un score que ordena las opciones por probabilidad de cierre. Desde ahí la propuesta viaja a una bandeja con negociación por turnos: contraofertas, historial de cada movimiento y estados explícitos de quién debe responder.
Tres movimientos y un eje que no se rompe
Una unidad, una sola vez
Datos base, valoración y modalidad de venta. Si admite cambio, los criterios de intercambio quedan escritos: marcas, rango de año, kilometraje máximo y condición mínima.
Datos base
Valoración
Modalidad de venta
Revisión
¿Cómo quieres vender esta unidad?
Marcas que aceptas a cambio
2015 — 2024
120.000 km
Buena
El motor cruza toda la red
Los criterios de tu ficha se comparan contra el inventario del resto de concesionarios. Cada coincidencia vuelve con un score de 0 a 100 y con el diferencial ya calculado.
La conversación empieza con la cifra puesta
La propuesta viaja a la bandeja del otro dealer con el cálculo desglosado. A partir de ahí, negociación por turnos: contraofertas, historial y estados explícitos de quién debe responder.
Cinco decisiones que hacen confiable el número
Motor de matches con score explicado
Cada match llega con un anillo de score 0-100 y un desglose por criterios, financiero, reputación y geografía. La vista incluye una tarjeta que explica en texto plano cómo se calcula, para que el dealer confíe en el orden de la lista.
Diferencial en dos direcciones
El mismo número se lee distinto según de qué lado estés: se firma con +1 o −1 según seas proponente o contraparte y se etiqueta como «a tu favor» en verde, «a compensar» en ámbar o «cambio par» en neutro.
Negociación por turnos
Aceptar, contraofertar y rechazar solo aparecen cuando la API marca que el turno es tuyo. Si le toca al otro dealer, los botones se sustituyen por un estado de espera con el historial completo de la negociación debajo.
Oferta en efectivo que reemplaza el cálculo
Un dealer puede escribir un monto manual en USD que sustituye por completo al diferencial automático, comisión incluida. Las líneas del cálculo original quedan atenuadas en pantalla como referencia en vez de desaparecer.
Sesión que sobrevive a la red
El refresco de token se ejecuta en una sola promesa compartida para evitar carreras, y un 500 o una caída de red no borran la sesión: solo un 401 o 403 explícito cierra al usuario.
El score se dibuja y se explica
Un anillo de 0 a 100, cuatro criterios con su peso y una lista ordenada por probabilidad de cierre. El mismo componente que ve el dealer dentro de la aplicación.
El anillo pasa de gris a ámbar al cruzar 70 y de ámbar a verde al cruzar 85. El orden de la lista se justifica con el desglose: nada de una cifra sin explicación.
Cambios posibles
32 vehículos de la red son compatibles con tu inventario
32
14
9
Autos del Este
compatibilidad
Toyota Corolla 2019
$14.200
Ford Ranger 2018
$18.600
Motores Caribe
compatibilidad
Chevrolet Tahoe 2016
$21.500
Hyundai Tucson 2020
$19.300
Dealer Anzoátegui
compatibilidad
Jeep Cherokee 2017
$17.800
Mazda CX-5 2019
$17.800
Cruce de criterios declarados, cercanía de valor entre las dos unidades, reputación del concesionario y distancia geográfica. Cada factor aporta su parte al total de 100.
Cambios posibles (motor de matches)
Lo que ofrezco, lo que recibo y lo que falta por pagar
Dos tarjetas idénticas enfrentadas y, debajo, el cálculo abierto. Escribe un monto en efectivo y el desglose automático se atenúa: sigue ahí, como referencia, pero ya no manda.
Propuesta de cambio
Revise los detalles y términos del intercambio
Toyota Corolla LE 2019
68.400 km · Gris plata
Ford Ranger XLT 2018
91.200 km · Blanco
Oferta en efectivo (opcional)
a compensar
Propuesta de cambio · prueba a escribir un monto
Un mismo número, dos lecturas
El diferencial que devuelve la API está siempre en la perspectiva de quien propuso. La contraparte lo ve firmado con −1, con su etiqueta y su color: verde a favor, ámbar a compensar.
El neto no es el negociado
El diferencial negociado y el neto —que ya incluye comisión de plataforma del 0,8 % y costo de traspaso— viven en campos distintos y se resuelven en un módulo con pruebas propias.
El efectivo manda cuando existe
Si el dealer escribe un monto, ese importe sustituye por completo al cálculo. Las líneas originales quedan al 50 % de opacidad en lugar de desaparecer.
Tres estados y un solo número
Baja despacio: la barra bascula según de qué lado cae el valor.
Los botones solo aparecen cuando te toca
Un indicador de turno derivado del dealer que la API marca como pendiente de respuesta. Si le toca al otro, aceptar, contraofertar y rechazar desaparecen y queda un estado de espera con el historial completo debajo.
Te propongo la Ranger por tu Corolla. El diferencial lo calculó la plataforma.
−$4.400
Contraoferto. Puedo llegar ahí si el traspaso corre por tu cuenta.
−$3.900
Traspaso incluido y cerramos en esa cifra.
−$4.150
Aceptada. Coordinamos la entrega el jueves.
−$4.150
Propuestas
Autos del Este
4,8 · Barcelona, Anzoáteguiverificado
12/05/2026 · 09:24
Toyota Corolla LE
2019 · 68.400 km
$14.200
Ford Ranger XLT
2018 · 91.200 km
$18.600
Autos del Este−$4.400
Diferencial calculado por la plataforma
Tú−$3.900
Puedo llegar hasta ahí si incluyes el traspaso
Autos del Este−$4.150
Traspaso incluido. Cerramos en esa cifra
Motores Caribe · solo efectivo
Oferta directa por tu Chevrolet Tahoe 2016
Bandeja de propuestas · cambia de pestaña para ver el turno
Todo empieza en el radar
Nueve vistas renderizadas condicionalmente desde un estado currentView, sin rutas de URL. Ésta es la primera.
Hola, Arturo
Hay 12 matches esperando tu revisión
24
↑ +3
12
↑ +5
6
↑ +2
9 d
↑ −2
Matches urgentes
Ford Ranger XLT 2018
Autos del Este
Hyundai Tucson GLS 2020
Motores Caribe
Kia Sportage 2019
Dealer Anzoátegui
Embudo del mes
Inicio del dealer
Las maquetas reproducen la interfaz real; los datos que muestran son de ejemplo.
Lo que ya está construido, a un lado y otro del eje
Una capa de integración entre el prototipo y la API
SPA de una sola página montada desde src/main.tsx: AuthProvider envuelve la app y un AppShell la vuelve a montar con la identidad del usuario como key, de modo que cambiar de sesión limpia todo el estado. La navegación no usa rutas de URL sino un estado currentView con nueve vistas (dashboard, marketplace, matches, detail, requests, inventory, wizard, profile, settings) renderizadas condicionalmente desde src/app/App.tsx, con un guard que impide salir del asistente mientras se está publicando. Toda la comunicación pasa por src/lib/api.ts: un wrapper de fetch tipado que inyecta el JWT, desenvuelve el sobre { data } de la API, reintenta una vez tras refrescar el token —con una única promesa en vuelo para que varias peticiones simultáneas no disparen varios refrescos— y traduce el error al español antes de mostrarlo. src/lib/types.ts replica los esquemas Pydantic del backend y src/lib/proposals.ts y src/lib/datetime.ts concentran las dos reglas de negocio delicadas: el signo del diferencial y la interpretación de fechas UTC sin zona horaria en hora de Caracas. La capa visual es doble: Tailwind 4 más shadcn/ui para primitivas, y encima un design system propio en src/styles/redesign.css con tokens (--bg-0, --ink-0, --accent) y clases ds-* que redefinen incluso las utilidades emerald de Tailwind para unificar el aspecto sin reescribir cada componente. El panel de plataforma vive aparte en src/app/AdminPanel.tsx con su propia barra lateral oscura.
src/app/App.tsx
9 vistas por estado
src/lib/api.ts
fetch tipado + JWT
src/lib/types.ts
espejo de Pydantic
src/lib/proposals.ts
signo del diferencial
src/lib/datetime.ts
UTC → Caracas
src/styles/redesign.css
tokens y clases ds-*
src/app/AdminPanel.tsx
panel de plataforma
Cinco cosas que hubo que arreglar
A la izquierda el problema, a la derecha lo que se hizo. El eje se mantiene.
El punto de partida era un prototipo generado en Figma Make: bonito, navegable y completamente falso. Todos los números estaban escritos a mano dentro de los componentes.
Se construyó una capa de integración aislada (api.ts, auth.tsx, types.ts) espejo de los esquemas del backend, y App.tsx pasó a cargar cada vista por efecto. Los datos de ejemplo quedaron como respaldo: si la API no responde aparece un aviso y el prototipo sigue siendo demostrable sin levantar Docker.
Cualquier error 500 o corte momentáneo de red expulsaba al dealer de la sesión, porque el manejo de fallos borraba el token ante cualquier excepción.
El refresco de token se centralizó en una promesa compartida y el hidratado inicial ahora solo limpia credenciales ante un 401 o 403 explícito. Los errores de red y los 5xx dejan la sesión intacta y la siguiente petición reintenta.
Ambos dealers podían actuar sobre la misma propuesta a la vez, con contraofertas cruzadas y sin saber a quién le tocaba responder.
Se derivó un indicador de turno comparando el dealer que la API marca como pendiente de respuesta con el dealer del usuario. Aceptar, contraofertar y rechazar solo se renderizan cuando el turno es propio; en caso contrario aparece un estado de espera explícito.
El diferencial que devuelve la API está siempre en la perspectiva de quien propuso, así que la contraparte veía el signo invertido y leía como ganancia lo que era un pago.
Se extrajo a un módulo propio con pruebas la resolución del signo (+1 proponente, −1 contraparte) sobre el diferencial negociado, deliberadamente distinto del neto que ya incluye comisión y costo de traspaso, y se le asignaron etiquetas y colores fijos: verde a favor, ámbar a compensar.
Los mensajes de error del backend llegaban a la interfaz tal cual: cadenas en inglés, estados internos como pending o countered, y a veces páginas HTML completas de error.
Un sanitizador detecta respuestas HTML o demasiado largas y las reemplaza por un mensaje por código de estado, traduce los estados y frases conocidas al español y deja pasar el resto sin tocar, con pruebas unitarias que fijan ese contrato.
El tamaño real del trabajo
9
vistas del panel de dealer
52
métodos de API tipados en la capa de integración
28
pruebas unitarias con Vitest
46
componentes shadcn/ui en el design system
4
pasos en el asistente de publicación
14.316
líneas de TypeScript y TSX en src/
Con qué está construido
SwapDealers es una plataforma B2B cerrada que interconecta los inventarios de concesionarios de vehículos usados para que puedan intercambiar unidades entre ellos en lugar de esperar a un comprador final.
Cada vehículo se publica con una modalidad de venta —solo efectivo, solo cambio o ambas— y, cuando admite cambio, con criterios de intercambio propios: marcas aceptadas, rango de año, kilometraje máximo y condición mínima.
Un motor de matches cruza esos criterios contra el resto de la red y devuelve un score de compatibilidad junto con el diferencial monetario a favor o a compensar, para que la conversación entre dealers empiece con una cifra sobre la mesa.
La SPA en React consume una API FastAPI mediante una capa de fetch tipada con JWT, refresco de token y traducción de errores al español, y mantiene el prototipo navegable con datos de ejemplo cuando el backend no responde.
Editorial ejecutivo y cálido: papel hueso en vez de blanco puro, tinta casi negra, bordes de medio píxel y un único verde eléctrico reservado para la señal —score alto, diferencial a favor, cierre confirmado—, con ámbar para lo que hay que compensar. Tipografía Geist para la interfaz, Geist Mono con cifras tabulares en todo lo monetario e Instrument Serif en cursiva como acento editorial en los titulares.
Dos columnas que terminan siendo una sola tarjeta
Cambio confirmado
−$4.150
SwapDealers
¿Quieres algo así para tu producto?
Una plataforma B2B cerrada donde el número que abre la negociación tiene que ser correcto en las dos direcciones. Si necesitas una SPA que hable en serio con una API —sesión resistente, errores traducidos y reglas de negocio con pruebas—, es exactamente el terreno que conozco.