ZapOrca es un MVP de presupuesto para prestadores de servicios autónomos: electricista, pintor, plomero, armador de muebles. El prestador arma la propuesta en el celular en tres pasos, define el anticipo que quiere recibir y manda todo por WhatsApp, con el código Pix del anticipo en el propio texto. Es una aplicación web escrita en TypeScript, sin servidor: los datos quedan en el navegador del dispositivo de quien la usa.

Este caso técnico muestra lo que hace el código, cómo se arma el Pix sin intermediario, los errores que se volvieron regla y lo que un MVP sin usuarios todavía no prueba. Los números se verificaron en el repositorio en la versión del 30/10/2026, la más reciente.

Transparencia: ZapOrca fue concebido y desarrollado por Jeremias Cardoso, autor de este blog. El texto no cita empresa, personas ni ciudad, y deja fuera credenciales y detalles de seguridad.

Nota de actualización (30/10/2026): este post se reescribió como caso técnico. La versión del 21/09/2026, ya corregida el 29/10 sobre el QR Code dinámico, también decía que los presupuestos se sincronizaban con un servidor cuando volvía la conexión, que los datos quedaban en una base PostgreSQL con control de acceso por fila y que la validación usaba la biblioteca Zod. Verificado en el código, el producto publicado no tiene servidor desde el 09/10/2026, la validación es propia y la propuesta en PDF sale de la impresión del navegador. El enlace de la propuesta, que la versión anterior presentaba como el camino del cliente, solo abre en el dispositivo de quien la creó; desde el 30/10/2026 el código Pix va en el texto del mensaje. Este texto describe lo que hace el código.

El problema: el presupuesto que se vuelve una conversación suelta

El cliente pide un presupuesto, y el prestador responde con un mensaje de texto corrido o con una foto de un papel. Faltan el número de la propuesta, la validez, el valor del anticipo y la forma de pagar. Cuando el cliente acepta, alguien todavía tiene que pasar la clave Pix, y el valor del anticipo se escribe a mano, con chance de error de los dos lados.

ZapOrca ataca ese tramo, y solo ese: transformar lo que el prestador sabe del servicio en una propuesta con ítems, total, anticipo, saldo y plazo, y entregar al cliente un mensaje que ya trae el código Pix del anticipo con el valor correcto. El resto de la relación sigue siendo humano. Es la misma línea de otros casos del blog, como el catálogo que cierra pedidos en WhatsApp: automatizar el artefacto, no la conversación.

El MVP en números

Números del repositorio el 30/10/2026, fecha del último commit.

El MVP en números
MedidaValor
Código de la aplicación, sin líneas en blanco y sin comentarioscerca de 7,5 mil líneas: 6.451 en TypeScript, 1.017 de estilos y 68 en la página y en el script de tema
Código de pruebas1.915 líneas, con 131 pruebas en 15 archivos
Pruebas en esta revisión (30/10/2026)131 de 131 aprobadas; compilación de producción sin error
Dependencias en tiempo de ejecuciónninguna: el proyecto declara solo herramientas de desarrollo
Tamaño de la compilación202 kB de JavaScript (51 kB comprimido) y 67 kB de estilos
Historial en Git11 commits, del 04/09 al 30/10/2026
Primer commit (04/09/2026)38 archivos y 10.362 líneas: el MVP ya existía cuando pasó a versionarse
Catálogo listo43 ítems de servicio y material en 8 nichos, y 7 cláusulas de contrato
Versión1.0.0, sin tag

El repositorio no registra ningún prestador usando el producto. La tarea de invitar a los primeros diez prestadores conocidos por WhatsApp, sin medios pagos, consta como no iniciada.

Tres pasos en el celular

La propuesta nace en un asistente de tres pasos: el cliente, los ítems y el cierre. En el primero entran el nombre y el WhatsApp del cliente y el título del servicio, que son obligatorios, y, si el prestador quiere, la dirección de la obra y el plazo. En el segundo, cada ítem tiene descripción, cantidad, unidad y valor unitario, y el subtotal se calcula en el momento. Para no escribir todo desde cero, hay un catálogo con 43 ítems listos en 8 nichos: electricidad, pintura, hidráulica, aire acondicionado, armado de muebles, reparaciones menores, obras y yeso, y limpieza.

En el tercer paso quedan el descuento, en valor fijo o en porcentaje, el anticipo (sin anticipo, 30%, 50% o 100%) y un texto libre de términos, plazos y garantía. Siete cláusulas listas pueden entrar en ese texto con un toque: garantía, retención del anticipo en caso de cancelación, alcance y retrabajo, liquidación en la entrega, materiales provistos por el cliente, limpieza de los escombros y uso de fotos del servicio.

La cuenta es simple y queda en una función propia, cubierta por pruebas. El descuento nunca supera el subtotal, el anticipo es un porcentaje del total entre 0 y 100, y el saldo es lo que queda. Todo valor se redondea a centavos en cada etapa.

Desde el 30/10/2026, el último paso tiene un bloqueo: sin una clave Pix válida del propio prestador en el perfil, el presupuesto no se crea. La aplicación avisa y abre el perfil. El motivo está en un comentario del código: sin esa clave, el Pix iría a otra persona o a ninguna parte.

El Pix armado en el propio dispositivo

El código Pix que el cliente pega en el banco es un texto en el estándar BR Code, definido por el Banco Central. ZapOrca arma ese texto en el navegador, sin llamar a ningún servicio de pago. El armado sigue el formato TLV, en el que cada campo lleva un identificador de dos dígitos, el tamaño y el valor:

  • el indicador de formato;
  • la marca de código de uso único, uno por presupuesto;
  • la cuenta del receptor: el identificador de Pix y la clave del prestador;
  • la moneda, con el código 986, del real;
  • el valor del anticipo, o el total cuando la propuesta es sin anticipo;
  • el país, el nombre y la ciudad del receptor, sin tilde y en mayúsculas, con 25 y 15 caracteres como máximo;
  • el identificador de la transacción, tomado del número del presupuesto.

Al final viene el CRC16, una suma de verificación de 16 bits que la aplicación del banco verifica antes de aceptar el código. El cálculo usa el polinomio 0x1021 con valor inicial 0xFFFF, y las pruebas verifican el resultado contra el valor de referencia de ese algoritmo.

Antes de entrar en el código, la clave pasa por dos etapas. La validación acepta los cinco tipos de Pix: CPF y CNPJ con los dígitos verificadores comprobados, teléfono, correo electrónico de hasta 77 caracteres y clave aleatoria. La normalización pone la clave en el formato en el que está registrada: CPF y CNPJ solo con dígitos, teléfono con +55 y DDD, correo electrónico y clave aleatoria en minúsculas. Una clave con puntuación o sin el código del país es el tipo de error que el banco del cliente rechaza, y la venta se enfría a mitad de camino.

Este es un Pix estático: el código carga la clave y el valor, y no apunta a un cobro alojado. Por eso ZapOrca no sabe si el cliente pagó. Quien marca “recibí el anticipo” es el prestador, después de mirar la aplicación del banco, y el propio mensaje avisa al cliente de que ZapOrca no confirma el pago.

El QR Code también se dibuja en el dispositivo. Usa el modo byte con corrección de error de nivel M, en una implementación propia que reemplazó a la biblioteca usada antes. El cambio se hizo con una red de seguridad: las matrices generadas por la biblioteca antigua para dos textos, uno corto y uno del tamaño de un código Pix, quedaron congeladas en archivos, y dos pruebas exigen que la implementación nueva reproduzca cada una, módulo a módulo.

Lo que va a WhatsApp

El mensaje lo arma la aplicación y se abre en el WhatsApp del prestador, ya con el número del cliente. Usa la negrita del propio WhatsApp y pone un hecho por línea: servicio, número, hasta seis ítems, total, anticipo, saldo al concluir, plazo, validez y condición. Si hay más de seis ítems, una línea avisa cuántos quedaron fuera. La condición de pago es un texto fijo, que habla de un 30% de anticipo, y va en el mensaje y en la propuesta incluso cuando el prestador elige otro porcentaje.

El código Pix solo entra en el texto cuando la clave es del propio prestador. Justo después vienen dos frases: el valor cae en la clave Pix del prestador, y ZapOrca no confirma el pago del banco.

Hay dos versiones del texto. La primera usa emojis para marcar cada línea. La segunda existe por un problema de WhatsApp en la computadora, que cambiaba parte de los emojis por un signo de interrogación. El código llama a esa versión el modo “Anti-’?’”: la misma información, con marcadores simples. El prestador elige la versión antes de enviar, y puede copiar el texto en lugar de abrir el enlace.

La propuesta en PDF es la impresión del navegador

La propuesta formal es una página HTML en formato A4, con el logotipo del prestador, los ítems y los totales. El botón “PDF” abre esa página en una ventana y llama a la impresión del navegador, en la que la persona elige guardar en PDF. También se puede descargar la misma propuesta como un archivo HTML.

Nada de eso va solo a WhatsApp. Lo que sigue por la conversación es el texto del mensaje; el PDF, cuando el prestador quiera mandarlo, es un archivo que adjunta a mano. El logotipo se reduce en el propio dispositivo a un máximo de 360 por 180 píxeles antes de guardarse, para que la propuesta abra rápido y quepa en el almacenamiento del navegador.

Los datos quedan en el dispositivo

El perfil, los presupuestos y la cola de acciones quedan en el almacenamiento del navegador. El perfil y los presupuestos también tienen copia en IndexedDB, una base del propio navegador con más espacio. La cuenta es opcional y local: el registro pide el consentimiento de la LGPD y graba la cuenta solo en ese navegador. La primera propuesta no exige cuenta.

La eliminación de la cuenta borra, en ese dispositivo, el perfil, los presupuestos, la cola, las transacciones y la cuenta. La confirmación exige escribir el correo electrónico de la cuenta, y el botón queda bloqueado hasta que el texto coincida.

El tema claro u oscuro y el idioma de la carcasa y de la página inicial (portugués, inglés y español) usan las mismas claves del portal de herramientas del autor, donde el proyecto registra ZapOrca como una puerta separada de las herramientas gratuitas. El asistente y la propuesta están solo en portugués.

Plan gratuito y ZapOrca Pro

El plan gratuito permite hasta cinco propuestas. El Pro libera propuestas sin límite, cambia el pie de la propuesta y permite exportar la lista a una hoja de cálculo CSV, con punto y coma y acentos preservados para abrir directo en Excel. Cuesta R$ 29,90 por año, sin renovación automática.

La compra es manual: el comprador hace un Pix, envía el comprobante por correo electrónico o WhatsApp y recibe un código de licencia, que escribe en la aplicación. La licencia puede desactivarse en ese dispositivo. No hay cobro recurrente.

Incidentes que se volvieron regla

  1. La nube que salió (08 y 09/10/2026). La primera versión tenía cuenta en la nube, sincronización con una base remota y reglas de acceso por fila. En la publicación en el portal, la decisión fue quitar todo eso, para que el prestador use el primer presupuesto sin depender de un servicio externo. Salieron el cliente de la base remota, la biblioteca de validación y la de QR Code, y el producto quedó sin ninguna dependencia en tiempo de ejecución. La regla que quedó en la memoria del proyecto: una tabla remota solo vuelve si el dueño decide tener servidor de nuevo.
  2. El techo de 5 MB (15/10/2026). Con logotipo e historial, el almacenamiento simple del navegador, de cerca de 5 MB, se quedaría corto. Los presupuestos y el perfil pasaron a tener copia en IndexedDB, y el logotipo pasó a reducirse antes de guardarse.
  3. El signo de interrogación en lugar del emoji (15/10/2026). En el WhatsApp de la computadora, parte de los emojis del mensaje llegaba como ”?”. Nació la segunda versión del texto, sin esos símbolos, con una indicación en la pantalla que explica cuándo usarla.
  4. Dos defectos de pantalla que ninguna prueba atrapó. El tema oscuro mostró fondo claro con letra clara, porque el tema del dispositivo y el tema elegido en el portal son cosas distintas, y solo la letra seguía el segundo. La hoja del Pix se abría sola, porque una regla de visualización empataba con la regla que la ocultaba. Los dos se corrigieron en el estilo y quedaron registrados en las lecciones del proyecto. Una prueba automática de regla no atrapa ese tipo de defecto.
  5. El ejemplo que cobraba al autor (hasta el 30/10/2026). Quien abría la aplicación por primera vez recibía un perfil de ejemplo con la clave Pix real del autor. Un prestador que hiciera un presupuesto sin editar el perfil mandaría al cliente un Pix que pagaba al autor. Hoy la aplicación empieza sin clave, los presupuestos de ejemplo usan la clave aleatoria nula, que no pertenece a nadie, y el presupuesto solo se crea con la clave del prestador. Quien ya tenía el perfil antiguo guardado en el dispositivo tiene la clave y los códigos Pix borrados en la apertura siguiente. La lección vale para cualquier producto: un dato de ejemplo es un dato de producción.
  6. El enlace que solo abría en el dispositivo de quien lo creó (hasta el 30/10/2026). El mensaje llevaba un enlace a la propuesta. Pero la propuesta vive en el navegador del prestador, y el enlace busca en ese almacenamiento: en el celular del cliente, la pantalla decía “Propuesta no encontrada o vencida”, y el código Pix solo existía ahí. La corrección fue poner el Pix de copiar y pegar en el texto del mensaje y quitar el enlace, y el botón de la pantalla de detalles pasó a copiar el código Pix. En un producto sin servidor, lo que tiene que llegar al cliente va dentro del mensaje.

Pruebas: muchas en la regla, ninguna en el navegador versionado

Las 131 pruebas corren con Vitest y cubren el armado del Pix y el CRC, la validación de claves y de CPF y CNPJ, el QR Code contra las matrices congeladas, el cálculo de totales y la máquina de estados del presupuesto, el mensaje de WhatsApp, el perfil de ejemplo, las cláusulas, el catálogo, la cuenta local, la eliminación de datos y la licencia Pro. En esta revisión, la suite corrió entera: 131 de 131, en 15 archivos, y la compilación de producción terminó sin error.

Dos cuidados al leer ese número. Primero, al menos 22 pruebas verifican piezas de la fase con servidor: 16 prueban un modelo en memoria de la antigua base remota, 4 prueban la reconciliación con la nube, que la aplicación ya no llama, y otras 2 cubren el vaciado de la cola y un aviso de pago simulado. Todavía pasan, pero no prueban nada sobre la aplicación actual. Segundo, no hay prueba de interfaz en el repositorio. La memoria del proyecto registra una ronda de pruebas en el navegador el 15/10, pero no está versionada, y fue en la pantalla donde nacieron los defectos de tema y de la hoja del Pix.

Lo que todavía no está resuelto

Los ítems de abajo vienen de la lectura del código. La suite se ejecutó, pero la aplicación no se usó en un navegador para esta revisión.

  • Ningún usuario todavía. El MVP no tiene registro de uso. Precio, plan gratuito y mensaje son hipótesis hasta que los primeros prestadores lo usen.
  • Los ejemplos cuentan para el techo del plan gratuito. La aplicación guarda tres presupuestos de ejemplo en la primera apertura, y la verificación del techo cuenta todos los presupuestos guardados. Quien no borra los ejemplos hace dos propuestas propias antes de ver la invitación al Pro.
  • La numeración puede repetirse. El número es “ORC-2026-” seguido de la cantidad de presupuestos guardados más uno. El año está fijo en el código, y borrar un presupuesto hace que el número siguiente repita uno que ya existe.
  • Un solo dispositivo. Limpiar los datos del navegador o cambiar de celular se lleva los presupuestos. La copia posible es descargar cada propuesta en HTML o, en el Pro, exportar la lista en CSV.
  • La cola sin destino. La cola de acciones se diseñó para un servidor. Sin él, vaciar la cola marca cada ítem como enviado sin enviar nada. El código de reconciliación con la nube también sigue en el repositorio.
  • Pago no confirmado. La aplicación no habla con ningún banco; el “recibí el anticipo” depende del prestador.
  • Condición de pago fija. El texto de la condición habla de un 30% de anticipo incluso cuando el prestador elige sin anticipo, 50% o 100%.
  • El enlace que quedó en los textos. El enlace de la propuesta salió del mensaje el 30/10/2026, pero la página inicial de la aplicación todavía promete “el enlace de la propuesta”, el mensaje con más de seis ítems todavía manda ver el resto “en el enlace” y el README todavía describe el enlace.
  • Publicación manual. Este texto describe el código del repositorio. La publicación en el portal es un paso aparte, hecho por el dueño.

Lecciones que valen fuera del presupuesto

  1. Un dato de ejemplo es un dato de producción. Una clave, un correo o un teléfono reales en un ejemplo terminan en la mano de quien no editó nada.
  2. Sin servidor, lo que el cliente necesita va dentro del mensaje. Un enlace que apunta al almacenamiento de otro dispositivo no abre.
  3. Quitar el servidor es una decisión de producto. Se gana costo cero y un comienzo sin registro; se pierde respaldo, segundo dispositivo y confirmación de pago.
  4. Al cambiar una biblioteca, congele su salida antes. La matriz antigua se volvió la prueba de la implementación nueva.
  5. Una prueba de arquitectura retirada engaña. Pasa e infla el total sin probar nada sobre el producto actual.
  6. Un conteo no es un identificador. Un número de documento que depende de cuántos existen se repite cuando algo se borra.
  7. Un MVP sin usuario es una hipótesis. El código listo no responde si alguien lo va a usar; solo los primeros prestadores responden. VE Facilites, un piloto todavía sin cliente contratado, y Embalo, todavía en implementación, están en el mismo punto.

Fuentes