Resumen del proyecto

Nuestro cliente opera una plataforma de cashback que permite a comercios físicos —cafeterías, salones, boutiques, comercio de barrio— recompensar a sus clientes y, no menos importante, por fin llegar a conocerlos. Los negocios de calle rara vez tienen los datos de cliente que las tiendas online dan por sentados: quiénes son sus habituales, cuándo vinieron por última vez, qué les hace volver. La plataforma cierra esa brecha poniendo un programa de cashback y fidelización en manos de cada comercio participante, y una app de marca en el bolsillo de cada cliente.

En lugar de publicar una sola app, el modelo de negocio pide una familia de aplicaciones: una app de consumo insignia donde los compradores descubren comercios participantes y siguen su cashback, una app específica para que los comercios se conecten y gestionen sus propias recompensas, y un catálogo creciente de apps de , cada una una app de cashback completamente personalizada y publicada de forma independiente para una marca socia o una cadena, todas movidas por el mismo producto.

Cuando el proyecto maduró, el ecosistema abarcaba más de 15 aplicaciones móviles en producción. El reto de ingeniería nunca fue construir bien una app: fue construir una base de código que pudiera convertirse en cualquier número de apps de cashback de marca sin que el coste de mantenimiento creciera linealmente con cada nuevo socio.

Fuimos responsables del sistema completo de principio a fin: la app de consumo compartida, la app de comercios, la flota de marca blanca, el motor de reglas de cashback y los servicios de backend, y las herramientas internas de administración que convirtieron «lanzar una nueva app de marca» de una tarea de ingeniería de varios días en un formulario autogestionado.

Bajo NDA

Este proyecto está cubierto por un acuerdo de confidencialidad. Se omiten el cliente, el nombre del producto y cualquier detalle identificativo, y el trabajo descrito a continuación se cuenta a nivel de arquitectura y no de detalles de implementación.

Inicio de la app de consumo con saldo de cashback y bonus por invitar amigos

Inicio de la app de consumo con saldo de cashback y bonus por invitar amigos

Detalle de comercio con porcentaje de cashback por compra

Detalle de comercio con porcentaje de cashback por compra

Cupones y novedades del comercio

Cupones y novedades del comercio

Configuración de una aplicación de marca blanca

Configuración de una aplicación de marca blanca

Lista de aplicaciones de marca blanca en la administración

Lista de aplicaciones de marca blanca en la administración

Una base de código, muchas apps

La app de consumo insignia y todas las variantes de marca blanca corren sobre una única base de código. No hay forks, ni ramas por marca, ni proyectos copiados y pegados que mantener sincronizados. Lo que difiere entre apps —marca, tema, identidad, feature flags, configuración de recompensas y metadatos de la ficha de tienda— se expresa enteramente como configuración que vive fuera del código.

Construimos el cliente en torno a un sistema de flavours y configuración: un plano binario único que resuelve su identidad de marca en tiempo de compilación a partir de un paquete de configuración por app. Colores, tipografía, logos, pantallas de inicio, iconos de app, identificadores de paquete y conjuntos de funciones activas se inyectan por flavour. Un bug arreglado una vez, o una funcionalidad entregada una vez, aterriza en todas las apps de la flota en la siguiente release: no hay divergencia por marca que mantener.

Es clave que las palancas que definen cada marca las manejan responsables sin conocimientos de programación. A través de la interfaz de administración, una persona no técnica define los iconos, colores, luminosidad (tema claro u oscuro) y determinados textos de una app nueva, y esas decisiones fluyen directamente a la compilación sin intervención de un desarrollador. Quienes son dueños del aspecto de una marca pueden cambiarlo directamente, en lugar de abrir un ticket y esperar a ingeniería.

Esta es la palanca económica central del proyecto: el coste marginal de la decimosexta app es casi cero, porque es el mismo código que la primera, con una configuración distinta.

Configuración de build nativa en Dart

Una flota de marca blanca vive o muere por la configuración de build nativa: los ajustes de Android e iOS que a las tiendas realmente les importan. Los application ID y los identificadores de paquete, los nombres visibles, los números de versión y de build, la configuración de firma, los iconos y recursos de splash y las entradas por flavour en build.gradle y en el proyecto de Xcode tienen que ser correctos para cada app y cada build.

En vez de mantener eso a mano, escribimos herramientas propias en Dart que gestionan programáticamente la configuración de build de Android e iOS. Dado el paquete de configuración de una marca, la herramienta reescribe las entradas correspondientes de Gradle, del manifiesto, del Info.plist y del catálogo de recursos para que encajen con el flavour objetivo antes de que se ejecute la compilación. Mantener esta lógica en Dart hace que comparta la misma fuente de verdad que el cliente Flutter y que se ejecute como un paso de primera clase de nuestro proceso de build, así que la configuración nativa de una marca se genera de forma determinista a partir de su configuración y nunca se edita a mano.

La app de comercios

Los comercios físicos necesitaban su propia herramienta, no una versión recortada de la vista de consumo, sino una app pensada para gestionar un programa de recompensas y entender a sus clientes. Desde la app de comercios, un dueño de tienda se conecta a la plataforma en minutos, define sus reglas de cashback y descuentos, confirma las compras de los clientes para otorgar cashback y, por fin, ve quiénes son sus clientes: nuevos frente a recurrentes, con qué frecuencia visitan y cómo funciona cada promoción. Para muchos de estos negocios es la primera visión estructurada de su base de clientes que han tenido nunca. La construimos sobre la misma base de Flutter y la misma librería de componentes compartida que las apps de consumo, así que las actualizaciones del sistema de diseño y las correcciones de plataforma se propagan a ambos públicos, mientras que los flujos específicos de comercio viven en sus propios módulos.

Reglas configurables de cashback y descuentos

El corazón de la plataforma es un motor de reglas flexible que permite a cada comercio diseñar sus propias recompensas sin nuestra ayuda. A través de la app de comercios, una tienda compone reglas como:

  • Cashback por compra: un porcentaje o cantidad fija devuelta al saldo del cliente en cada compra que cumpla los requisitos.
  • Bonus de cumpleaños: una recompensa acreditada automáticamente en torno al cumpleaños del cliente para hacerle volver a cruzar la puerta.
  • Bonus por invitación: una recompensa por recomendación que se paga cuando un cliente existente invita a un amigo que se registra y hace su primera compra.

Las reglas son datos, no código: cada comercio elige su combinación, fija los importes, los topes y las ventanas de validez, y el motor las evalúa en el momento de la compra. Como las reglas viven en la configuración, un comercio puede lanzar una campaña de cumpleaños o cambiar un porcentaje de cashback por sí mismo, al instante, en toda su app, y nosotros no publicamos ninguna release para soportarlo.

La administración y el pipeline de build automatizado

La pieza más destacada del sistema es la interfaz interna de administración. Incorporar una nueva marca de marca blanca solía ser un recado de ingeniería: crear la configuración, registrar los identificadores de paquete, generar los recursos de firma, montar las fichas de tienda y añadir el nuevo target a CI. Comprimimos todo eso en una única aplicación web que los responsables manejan sin escribir código.

Un responsable rellena un formulario —nombre de marca, tema, recursos, metadatos de tienda, selección de funciones— y el sistema hace el resto:

Generación de configuración: la administración persiste la configuración y los recursos de la nueva marca y produce el paquete de configuración por flavour que consume el cliente Flutter.

Registro en el pipeline: el nuevo target de app se registra automáticamente en el pipeline de . El sistema de build recoge el nuevo flavour, ejecuta nuestras herramientas en Dart para aplicar la configuración nativa de Android e iOS y produce artefactos firmados para ambas plataformas.

Lanzamientos autogestionados: lo que antes requería un desarrollador en el circuito para cada marca nueva pasó a ser un proceso repetible guiado por un formulario. El negocio puede escalar el número de apps publicadas sin escalar el tamaño del equipo de ingeniería.

Automatización de build y despliegue con Fastlane

Todo el proceso de compilación y publicación está automatizado de principio a fin con Fastlane, la cadena de herramientas de código abierto para automatizar build y despliegue móvil. La usamos para estandarizar cada paso que si no sería manual y propenso a errores en más de 15 apps: gestionar la firma y el aprovisionamiento, compilar y firmar los binarios de iOS y Android, y enviar cada app a la App Store y a Google Play junto con sus metadatos y capturas.

Como todas las apps comparten una única configuración de Fastlane parametrizada por flavour, publicar la flota entera es una operación única y repetible. Una nueva marca de marca blanca hereda exactamente el mismo camino de despliegue probado en combate que la app insignia, sin necesidad de scripts de release a medida.

La administración es una aplicación Vue respaldada por nuestros servicios en PHP y un almacén de datos PostgreSQL, con las herramientas de Ruby y Fastlane orquestando la automatización de build y publicación.

Backend y servicios

Bajo todas las apps hay un backend compartido que ejecuta el libro mayor de cashback, el motor de reglas, los perfiles de cliente y la configuración por marca. Un único conjunto de servicios sostiene la flota entera, con el contexto de marca resuelto en cada petición, de modo que un cliente en cualquier app de marca blanca, en la app insignia o un comercio usando la app de comercios está hablando con la misma superficie de API probada, acotada a su marca. El libro mayor registra cada acumulación y cada canje para que los saldos sean siempre auditables, y los perfiles de cliente dan a cada comercio esa visión sobre su público de la que el comercio físico suele carecer.

Deep linking diferido y el bonus por invitación

La funcionalidad que esto desbloqueó fue el bonus por invitación. Las recomendaciones son cómo crece la plataforma: un cliente satisfecho invita a un amigo, que toca el enlace de invitación, pero que casi nunca tiene todavía la app instalada. Con un corriente, ese contexto de invitación se perdía en el momento en que el amigo llegaba a la tienda: instalaba, abría la app, aterrizaba en una pantalla de inicio genérica y la conexión entre quien invita y quien es invitado desaparecía, y con ella el bonus por invitación prometido a ambos. El momento más viral del producto estaba roto en su paso más importante. Lo arreglamos con deep linking diferido para que la invitación sobreviva a la instalación.

Como toda la flota comparte una base de código, la funcionalidad se construyó una vez y todas las apps de marca —insignia, comercios y todas las variantes de marca blanca— la heredaron automáticamente. La implementamos con mecanismos de primera parte en lugar de con un servicio de terceros: un App Clip de iOS ligero captura el enlace de invitación antes de que exista la app completa y lo traspasa mediante un contenedor de App Group compartido, mientras que la API Install Referrer de Google Play lleva la carga útil en Android. Una cola de enlaces pendientes retiene la invitación hasta que la app está lista y el nuevo cliente se ha registrado e iniciado sesión; solo entonces se atribuye la recomendación y se acredita el bonus por invitación tanto a quien invitó como al nuevo cliente, de modo que la recompensa se resuelve correctamente aunque abarque una instalación y un inicio de sesión nuevo en un arranque en frío.

Escribimos el enfoque técnico completo —incluido por qué la solución habitual dejó de funcionar— en Deep linking diferido después de Firebase Dynamic Links: App Clips + Play Install Referrer.

Resultados

El cliente puede lanzar ahora una app de cashback completamente personalizada y lista para tienda para un socio nuevo en una fracción del tiempo que antes costaba, sin apartar ingenieros del trabajo de producto en cada lanzamiento. La arquitectura de base de código compartida mantiene más de 15 apps al mismo paso: una corrección, una funcionalidad, una release llega a todas. La administración convirtió un cuello de botella recurrente de ingeniería en una capacidad autogestionada, y el pipeline automatizado hizo de cada nuevo lanzamiento un evento predecible y repetible en vez de un proyecto a medida. Y los comercios físicos que antes iban a ciegas gestionan ahora sus propias campañas de cashback y descuentos y, por primera vez, saben quiénes son sus clientes.

Este es el tipo de plataforma que construimos en un encargo de desarrollo de apps de marca blanca: una base de código Flutter moviendo una flota entera de apps de marca.