Zizu
Una plataforma de delivery para todos los comercios de una ciudad, con cobros online.
Delivery para varios comercios, ArgentinaEn producción

- pruebas de punta a punta en cada cambio, más 57 unitarias
- 152
- migraciones versionadas que reconstruyen toda la base
- 118
- tablas con permisos por rol, con 64 políticas
- 30
- etapas entregadas, auditadas y facturadas
- 4
El problema
En una ciudad chica, pedir comida a domicilio es llamar o escribir por WhatsApp a cada comercio por separado. El comercio anota a mano, busca quién lleve el pedido y cobra como puede. El cliente no sabe en qué está su pedido y nadie sabe cuánto le corresponde a cada comercio.
El encargo era una sola app para todos los comercios de la ciudad, con repartidores propios y cobro con Mercado Pago o en efectivo.
Qué construí
Zizu, una plataforma de delivery donde el vecino pide, el comercio prepara, el repartidor lleva y la administración controla todo, cada uno desde su pantalla y viendo el mismo pedido actualizarse en vivo. La construí solo y de cero, y la entregué en cuatro etapas, cada una auditada y facturada.
Es una sola aplicación web en React 18 con Vite y TypeScript, instalable en el celular, con cuatro áreas según el rol. Cada área se carga por separado y se enciende con un interruptor por etapa: el código de un área apagada ni siquiera viaja al navegador.
El backend entero vive en Supabase, con 90 funciones de base, 5 Edge Functions y 3 tareas programadas con pg_cron:
- Las reglas están en la base, no en las pantallas. Row Level Security en las 30 tablas, con 64 políticas: un comercio no lee los pedidos de otro, y un repartidor dado de baja pierde en el acto el acceso a los datos de sus clientes.
- La máquina de estados del pedido corre en el servidor. Pendiente, aceptado, en preparación, listo, en camino, entregado: cada rol ejecuta sólo sus propias transiciones, aunque alguien llame a la API a mano.
- Tiempo real. El pedido nuevo suena en la pantalla del comercio sin recargar, el “listo” aparece en la lista de repartidores y el cliente ve cada paso.
- El precio lo calcula la base, con opciones y extras por producto. El total siempre sale del servidor.
También resuelve la operación diaria: tandas de hasta 4 pedidos por repartidor, horarios con excepciones que vencen solas, liquidaciones que cuentan sólo lo cobrado y auditoría de sólo agregar sobre 9 tablas.
Lo más difícil
Cobrar una sola vez, y que cada peso se pueda explicar. El aviso de pago llega a una Edge Function que valida la firma, descarta repetidos (Mercado Pago reintenta cada 15 minutos), consulta el pago directo a la API de Mercado Pago y le pasa el hecho a una función de la base que decide: acreditar, rechazar, registrar un contracargo o una devolución. El aviso transporta; la base decide.
Si el cliente reintenta el pago o abre dos pestañas, recibe el mismo cobro: guardo el intento vivo en la base y, si existe, ni se llama a Mercado Pago. Lo decidí después de probarlo, porque la clave de idempotencia de Mercado Pago no cubre la creación del cobro. Todo termina en un libro de cobros de sólo agregar, protegido por triggers: un asiento no se edita ni se borra, ni siquiera con acceso directo a la base, y la comisión queda sellada en cada pedido.
Que el repartidor llegue a la puerta correcta. Para convertir una dirección escrita en un punto del mapa armé dos capas con caché: primero OpenStreetMap y, de respaldo, Google. En un sistema así la falla peligrosa es el falso positivo: una consulta con sólo un número devolvía una puerta en otra ciudad a 500 km, y Google la marcaba con su máxima precisión. Por eso cada resultado se valida por localidad, distancia al centro, nombre de la calle y número de puerta, y si no pasa, se escala a la capa siguiente. Sin número de puerta no hay alfiler: un punto dudoso es peor que ninguno, porque el repartidor le cree. Las guardas son funciones puras, con pruebas unitarias sobre el callejero real de la ciudad.
Cómo se prueba
Cada cambio corre en GitHub Actions: 57 pruebas unitarias, chequeo de tipos, build y 152 pruebas de punta a punta con Playwright en un navegador real. Corren contra un ambiente de prueba separado e idéntico a producción, levantado con las mismas 118 migraciones. Cada push a la rama principal se publica solo en Vercel.
- Concurrencia real. Una prueba hace que dos repartidores tomen el mismo pedido a la vez: tomar es una sola operación atómica en la base, y gana uno solo.
- Los cobros, caso por caso. Sub-cobro y sobre-cobro, contracargos, devoluciones que respetan el cobro bueno, reintentos y el checkout abandonado que se cancela solo a los 30 minutos.
- Datos aislados. La suite crea sus propios datos de prueba, los borra al terminar y falla si el libro de cobros real creció durante la corrida.
Cómo funciona
- 01El cliente pidecarrito y opciones
- 02Total en la baseprecio del servidor
- 03Ubica la direccióncaché, OSM, Google
- 04Mercado Pagoo pago en efectivo
- 05Aviso de pagovalida y deduplica
- 05Comercio aceptaalarma en vivo
- 06Libro de cobrossólo agregar
- 06Repartidor tomaoperación atómica
- 07Entregadocada paso en vivo
- 07Liquidaciónsólo lo cobrado
Resultados
Cuatro pantallas, un mismo pedido
Cliente, comercio, repartidor y administración ven cada cambio de estado al instante, sin recargar.
Cobros que cierran
Mercado Pago confirmado de servidor a servidor, con devoluciones y contracargos, y un libro de cobros que no se puede editar.
Un pedido, un repartidor
Si dos repartidores tocan "Tomar" a la vez, gana uno solo. Una prueba automática lo verifica.
Direcciones confiables
Cada ubicación se valida antes de aceptarla, y el repartidor llega a la puerta que escribió el cliente.
Hasta 4 pedidos por viaje
El comercio agrupa pedidos en una tanda y el repartidor la toma entera en una sola operación.
Se instala como una app
Funciona en Android y iPhone sin pasar por las tiendas, y se actualiza sola después de cada versión.
Galería
Stack
- Aplicación
- React 18ViteTypeScriptTailwind CSSTanStack QueryZustandLeafletPWA con Workbox
- Datos y backend
- SupabasePostgreSQLRow Level SecurityRealtimeAuthStorageEdge Functions en Denopg_cron
- Integraciones
- Mercado PagoOpenStreetMapGoogle GeocodingResend
- Calidad y despliegue
- Playwrightnode:testGitHub ActionsVercel


