Tras pasar meses actualizando la lógica de precios, sabíamos que algo tenía que cambiar. Esta publicación detalla cómo reconstruimos la infraestructura de facturación de Webflow, brindando a los equipos la flexibilidad necesaria para lanzar actualizaciones sin cuellos de botella técnicos.
Patrón de estrategia para despliegues sin tiempo de inactividad
Implementamos el Patrón de Diseño de Estrategia en todos nuestros servicios de facturación para resolver el desafío de la migración gradual. Este patrón nos permitió mantener tres implementaciones distintas de cada servicio: una implementación de Stigg para espacios de trabajo inscritos, una implementación nula (no-op) para espacios de trabajo heredados y una implementación simulada para pruebas.
export function getEntitlementService(
opts: ServiceFactoryOptions
): EntitlementServiceInterface {
const loggerInstance = opts.logger ?? createDefaultLogger();
const eventEmitterInstance = opts.eventEmitter ?? getEventEmitter();
switch (serviceResolver(opts)) {
case SERVICE_PROVIDERS.MOCK:
return getTestingMockForService(StiggEntitlementService);
case SERVICE_PROVIDERS.NULL:
return new NullEntitlementService({
logger: loggerInstance,
eventEmitter: eventEmitterInstance,
});
case SERVICE_PROVIDERS.STIGG:
return new StiggEntitlementService({
logger: loggerInstance,
eventEmitter: eventEmitterInstance,
stigg: getConfiguredStiggClient(loggerInstance),
});
default:
throw new Error('Unknown service type');
}
}Lo mejor de este enfoque fue que el código que realizaba las llamadas no necesitaba saber qué estrategia estaba utilizando; invoca la misma interfaz y recibe un comportamiento consistente, ya sea que esté accediendo a la API en vivo de Stigg, a una implementación nula o a datos simulados:
const strategy = await getBillingServiceStrategy(workspaceId);
const service = EntitlementService(strategy);
const entitlement = await service.getBooleanEntitlement({
workspaceId,
featureId: CAN_LOCALIZE_CMS,
siteId,
});
if (entitlement.hasAccess) {
// has access to localize CMS
}Cada implementación de estrategia cumplía un propósito específico. Nuestra estrategia de Stigg gestionaba la integración completa con su API, incluida la transformación de datos entre su formato y el nuestro:
class StiggEntitlementService {
async getBooleanEntitlement(params: GetBooleanEntitlement) {
const entitlement = await this.stiggClient.getBooleanEntitlement(params);
const transformed = stiggToWebflowEntitlementTransformer(entitlement);
this.eventEmitter.emit('entitlement.get-boolean', transformed);
return transformed;
}
}Nuestra estrategia nula proporcionaba una implementación segura que no realizaba ninguna acción, pero que preservaba las capacidades de monitoreo:
class NullEntitlementService {
async getBooleanEntitlement(params: GetBooleanEntitlement) {
this.eventEmitter.emit('entitlement.get-boolean', params);
return {};
}
}Este patrón fue fundamental para el éxito de nuestra migración. Permitió despliegues sin tiempo de inactividad, la migración gradual de espacios de trabajo, pruebas exhaustivas con simulaciones y la flexibilidad de cambiar de proveedor de facturación en el futuro simplemente implementando nuevas estrategias.
Mantener dos sistemas sincronizados
El patrón de estrategia resolvió nuestro desafío de organización del código. Sin embargo, aún enfrentábamos un problema de coordinación: asegurar que los espacios de trabajo inscritos en nuestro despliegue mediante indicadores de funciones (feature flags) estuvieran correctamente inscritos en la plataforma de Stigg. Esta sincronización fue clave para mantener la consistencia de los datos mientras transferíamos la gestión de suscripciones de nuestro sistema heredado a Stigg.
El desafío principal era que teníamos dos sistemas independientes tomando decisiones de inscripción. Nuestro sistema de indicadores de funciones determinaba qué espacios de trabajo debían usar la nueva infraestructura de facturación, mientras que Stigg necesitaba saber qué clientes debía gestionar activamente. Una discrepancia entre estos sistemas podría resultar en inconsistencias de facturación o interrupciones del servicio.
Lo solucionamos con una función de sincronización de inscripción que se ejecuta cada vez que un espacio de trabajo interactúa con nuestro sistema de facturación:
export async function isStiggBillingSyncEnabled(
workspace: Workspace
): Promise<boolean> {
try {
return await getAndSetRolloutValue(workspace);
} catch (err: Error) {
if (shouldRunCustomerBackfill(err.message)) {
try {
await backfillMissingCustomer(String(workspace._id), err.message);
return await getAndSetRolloutValue(workspace);
} catch (backfillError: BackfillError) {
logger.error('Error backfilling Stigg customer', err);
}
}
return false;
}
}
async function getAndSetRolloutValue(workspace: Workspace) {
const isEnrolled = featureConfig.getFeatureFlag(FEATURE_FLAG);
await ensureEnrolledInStigg(workspace, isEnrolled);
return isEnrolled;
}Esta función se convirtió en nuestra fuente de verdad para la conciliación. Detectaba discrepancias entre nuestros indicadores de funciones y el estado de inscripción en Stigg, las corregía automáticamente y almacenaba los resultados en caché para minimizar el impacto en el rendimiento.
Rendimiento y fiabilidad
El nuevo sistema de facturación ofreció mejoras de rendimiento notables en toda la plataforma.
- Al eliminar las llamadas síncronas a la API de Stripe que anteriormente bloqueaban cada cambio de plan, logramos una reducción del 95% en las operaciones de sincronización para espacios de trabajo con un gran número de sitios. Este cambio arquitectónico eliminó un cuello de botella importante que causaba tiempos de espera y degradaba la experiencia del usuario.
- En nuestro sistema de derechos, reemplazamos una configuración estática de capacidades por comprobaciones de derechos dinámicas y almacenadas en caché, lo que proporcionó un seguimiento centralizado del uso, algo que nunca habíamos tenido. Anteriormente, diferentes funciones implementaban sus propios métodos de seguimiento (o no realizaban seguimiento alguno), lo que generaba inconsistencias y sobrecarga de rendimiento. El nuevo sistema mejoró los tiempos de carga de las páginas y redujo la complejidad del código en toda la plataforma.
- La estrategia de almacenamiento en caché que implementamos eliminó las llamadas redundantes a la API, detectó y corrigió automáticamente las inconsistencias de datos y aseguró que el sistema permaneciera funcional incluso durante interrupciones de servicios externos. Esta resiliencia fue clave durante el período de migración, cuando necesitábamos mantener la fiabilidad del servicio mientras coordinábamos múltiples sistemas.
- Desarrollamos estrategias de manejo de errores diferenciadas según la importancia de cada operación. Clasificamos los fallos de inscripción como críticos para evitar inconsistencias en la facturación y registramos las operaciones menos críticas sin interferir con los flujos de trabajo de los usuarios. Además, implementamos una lógica de relleno integral para abordar casos excepcionales, como restauraciones de espacios de trabajo, clonación de sitios y fallos temporales del sistema.
Durante todo el despliegue, monitoreamos el rendimiento de cerca con paneles de DataDog dedicados que rastreaban las tasas de aciertos de caché, los tiempos de respuesta de la API, los fallos de sincronización y las discrepancias de inscripción en tiempo real. Este monitoreo resultó invaluable para identificar y resolver problemas antes de que pudieran afectar a los clientes y nos dio la confianza para acelerar el cronograma de despliegue.
Reflexiones sobre la migración
La migración al nuevo sistema de facturación ha transformado la forma en que manejamos los cambios de precios y paquetes. Lo que antes requería meses de esfuerzo de ingeniería se ha convertido en un trámite sencillo, permitiendo ahora a los gestores de producto actualizar planes y derechos con poca o ninguna intervención técnica. Este cambio ha facultado a los equipos para implementar modificaciones de manera rápida y segura.

Las decisiones de diseño estratégico y la documentación exhaustiva también han permitido a los equipos de producto añadir nuevas funciones y derechos con una mínima orientación por parte del equipo de Suscripciones y Pagos. Aunque seguimos limpiando las secciones restantes del sistema heredado, esto ha sentado una base sólida para el crecimiento y la innovación futuros en Webflow.
Lecciones aprendidas
La migración de un sistema clave como la facturación nos dejó lecciones valiosas que guiarán nuestras futuras migraciones a gran escala:
- Identifica todos los casos excepcionales desde el principio, especialmente los flujos de trabajo entre sistemas. Pasamos por alto flujos como restauraciones, reversiones de instantáneas y transferencias de espacios de trabajo. Estos escenarios olvidados provocaron discrepancias en las suscripciones que tuvimos que corregir manualmente. Ahora, catalogamos sistemáticamente todos los flujos que interactúan con el sistema de migración antes de empezar a implementar nada.
- Planifica los límites de tasa y las restricciones de las API externas desde el primer día. Debido a los espacios de trabajo con muchos sitios, nos topamos con límites de tasa en la API de Stigg que causaron interrupciones en el servicio. Trabajamos con Stigg para aumentar los límites y aprovechamos una API de borde respaldada por DynamoDB para reducir la dependencia de consultas externas en tiempo real y mejorar la resiliencia.
- Limpiar el código heredado es más complejo que la migración inicial. Aunque el nuevo sistema funcionaba de maravilla, eliminar las implementaciones antiguas resultó ser más complicado de lo previsto. Coordinar con los equipos para migrar a los nuevos derechos de acceso sin degradar el rendimiento requirió una planificación cuidadosa y pruebas exhaustivas. Aprendimos a reservar más tiempo para las fases de limpieza en futuras migraciones.
- La monitorización y la observabilidad aceleran la migración. Nuestros completos paneles de DataDog no solo nos ayudaron a detectar problemas, sino que nos dieron la confianza para avanzar más rápido. La visibilidad en tiempo real de las tasas de acierto de caché, los tiempos de respuesta de la API y el estado del sistema nos permitió acelerar los plazos de lanzamiento, ya que podíamos identificar y resolver problemas antes de que afectaran a los clientes.
Conclusión
Reconstruir nuestra infraestructura de facturación fue una tarea compleja pero necesaria para respaldar la próxima década de crecimiento de Webflow. Esto nos ha proporcionado una base flexible y escalable que reduce el esfuerzo de ingeniería necesario para gestionar cambios en precios y paquetes, a la vez que respalda mejor nuestro crecimiento futuro y las expectativas de nuestros clientes.
Entre los principales logros de esta migración, hemos mejorado drásticamente la eficiencia de nuestras actualizaciones de facturación, permitiendo realizar en una fracción del tiempo cambios que antes llevaban meses. El nuevo sistema nos permite introducir nuevas funciones y modelos de precios sin el esfuerzo titánico que requería antes. Se ha diseñado pensando en la escalabilidad, listo para soportar la creciente base de usuarios de Webflow sin convertirse en un cuello de botella. Hemos logrado mejoras notables en la latencia, eliminando las llamadas API síncronas que antes causaban tiempos de espera y ofreciendo operaciones de facturación más rápidas y fiables en toda la plataforma. Otro resultado importante de este proyecto ha sido la decisión de encapsular las herramientas de terceros detrás de una capa de servicio interna. Este patrón simplificó el despliegue actual y garantizó que podamos cambiar de proveedores en el futuro sin necesidad de realizar cambios importantes en nuestro código.
Mirando hacia el futuro, aún queda mucho por construir. Hemos sentado las bases, pero muchos de los problemas más desafiantes y gratificantes en facturación, derechos de acceso y monetización aún están por llegar. Si te entusiasma resolver este tipo de retos, nos encantaría saber de ti: echa un vistazo a nuestras vacantes.

¡Estamos contratando!
Buscamos talento en producto e ingeniería para que se una a nuestra misión de poner superpoderes de desarrollo al alcance de todos.










