Bid2Drive — Diseño y desarrollo de una plataforma de subastas de vehículos
Proyecto de ingeniería centrado en los desafíos de concurrencia en tiempo real, fiabilidad y orquestación asíncrona de eventos requeridos para subastas automovilísticas seguras y auditables.
Frontend Reactivo
Nuxt 3 / Vue con actualización reactiva de contadores de subasta y WebSocket streams para pujas en directo.
API Gateway & Atomic Locks
Django REST Framework procesando pujas dentro de bloques select_for_update() para serializar colisiones.
Async & Escrow
Celery Beat gestionando la cuenta atrás con prórroga anti-snipping y Stripe reteniendo fondos de garantía.
Contexto: qué problema resuelve el proyecto
Las subastas de vehículos de ocasión presentan una complejidad técnica singular: a diferencia del comercio electrónico convencional donde el inventario es estático, en una subasta el precio, el adjudicatario provisional y el tiempo restante fluctúan segundo a segundo.
El problema crítico en estos entornos es la integridad concurrente: cuando múltiples usuarios pujan en el último segundo por un vehículo de alto valor, un sistema sin sincronización estricta corre el riesgo de registrar dos pujas con el mismo importe o validar una puja posterior al cierre formal.
Bid2Drive nace como proyecto personal con el objetivo específico de profundizar en este problema de ingeniería: diseñar una arquitectura capaz de manejar pujas de alta frecuencia, resolver condiciones de carrera en base de datos y coordinar eventos temporales asíncronos con fiabilidad absoluta.
Mi contribución: qué hice personalmente y con quién trabajé
Al tratarse de un proyecto personal en desarrollo, asumo el diseño de arquitectura y la implementación técnica de extremo a extremo:
- Modelado de base de datos relacional: Definición de modelos en PostgreSQL para usuarios, subastas, vehículos, historiales de puja y registros de auditoría inmutables.
- Lógica transaccional de puja: Implementación del motor de pujas en Django con serialización estricta de transacciones y cálculo dinámico de incrementos mínimos.
- Infraestructura asíncrona: Configuración de Redis como broker y caché de estado en memoria, junto con workers de Celery para planificar cierres de subasta y extensiones dinámicas de tiempo.
- Integración con pasarela Stripe: Diseño de un flujo de pre-autorización de fondos (hold de tarjeta) que garantiza que un usuario cuenta con saldo suficiente antes de pujar, liberando la retención si es superado.
- Cliente web prototipo: Creación de una interfaz reactiva en Nuxt / Vue para la monitorización en vivo del catálogo de vehículos y el tablero de pujas.
Decisiones técnicas: qué opciones valoré y por qué escogí una
Cada decisión de arquitectura en Bid2Drive estuvo guiada por priorizar la consistencia frente a la velocidad superficial:
Base de datos: PostgreSQL con bloqueos sobre bases de datos NoSQL
Aunque bases NoSQL como MongoDB ofrecen inserciones rápidas, carecen de las garantías ACID estrictas que exige un flujo monetario. En PostgreSQL, el uso de select_for_update() permite bloquear a nivel de fila la subasta mientras se valida y persiste la nueva puja más alta, garantizando coherencia absoluta.
Temporizadores: Celery + Redis sobre bucles de consulta activos (polling)
Consultar la base de datos cada segundo para comprobar si una subasta ha expirado colapsa las conexiones con miles de usuarios. Mediante tareas programadas de Celery con cuentas atrás (countdown) o tareas diferidas (ETA), el cierre se ejecuta de forma desacoplada y eficiente.
Seguridad financiera: Pre-autorización diferida (Separate Auth & Capture)
En lugar de cobrar inmediatamente o confiar en cobros posteriores al cierre, se utiliza la API de PaymentIntents de Stripe en modo manual (capture_method='manual'). Esto retiene una fianza temporal que disuade de ofertas falsas y evita costes de devolución.
Retos y soluciones: dificultades encontradas y cómo las resolví
El problema del "Snipping" en el último segundo
Problema: En las subastas online, los usuarios suelen esperar a los últimos 3 segundos para lanzar su puja, impidiendo que otros compradores puedan reaccionar y desvirtuando el valor real del vehículo.
Solución: Implementación de una regla de "prórroga automática" (Soft Close): si se registra una puja válida dentro de los últimos 2 minutos de la subasta, la tarea de Celery amplía automáticamente el tiempo de cierre en 2 minutos adicionales y notifica a los participantes.
Concurrencia extrema y prevención de condiciones de carrera
Problema: Dos compradores pulsan el botón de puja a 15.000 € en el mismo milisegundo. Ambas peticiones leen el estado actual (14.500 €) como válido y ambas intentan registrar 15.000 €.
Solución: Encapsulación del procesamiento dentro de una transacción atómica (@transaction.atomic) y bloqueo exclusivo de la fila de la subasta. La primera puja se procesa y actualiza el precio a 15.000 €; la segunda lee inmediatamente el nuevo precio y se rechaza limpiamente con un error explicativo.
Resultado: qué se ha conseguido hasta la fecha
Como proyecto de ingeniería en desarrollo activo, los resultados se evalúan en base a robustez arquitectónica y pruebas de carga internas:
El prototipo funcional valida que la arquitectura elegida soporta la operativa completa de subastas vehiculares: creación de lotes, inspección de características técnicas de los coches, gestión de depósitos de garantía y liquidación automática tras el martillazo final.
Aprendizajes: qué harías de otra manera hoy
El desarrollo de un sistema de subastas exige pensar en fallos desde el primer día. Las principales conclusiones de este ejercicio técnico son:
- Adopción temprana de WebSockets dedicados: En las primeras pruebas el refresco se basó en peticiones periódicas cortas (short-polling). Migrar a un canal WebSocket bidireccional (vía Django Channels o un broker ligero) reduce drásticamente el consumo de red en el cliente y la carga en el servidor.
- Auditoría inmutable de eventos (Event Sourcing): En entornos transaccionales donde se mueven sumas elevadas, guardar solo el estado actual es insuficiente. Diseñar un registro inmutable append-only donde cada puja y cada cambio de estado quede sellado con timestamp es fundamental para resolver disputas entre pujadores.
- Simulación de latencias de red variables: Probar la concurrencia en local no reproduce los 150ms de latencia que puede experimentar un usuario en red móvil 4G. Es crucial introducir retardos artificiales en los tests para certificar que la experiencia de usuario se mantenga justa y predecible.