Ejemplo de diagrama de estados: el ciclo de vida de una suscripción como máquina de estados

Un diagrama de máquina de estados UML resuelto para una suscripción SaaS: estados, eventos, guardas, elecciones, un estado compuesto y los errores que detecta pronto.

· Fundador y desarrollador

Publicado el

Ejemplo de diagrama de estados: el ciclo de vida de una suscripción como máquina de estados

Los errores de suscripción son errores de estado. Un cliente conserva el acceso después de cancelar. Una cuenta con pagos vencidos paga y sigue bloqueada. Una prueba termina para alguien sin tarjeta y ninguna regla dice qué pasa después. Cada uno de estos casos es una transición que nadie dibujó.

Un diagrama de máquina de estados, normalmente llamado diagrama de estados, enumera cada estado en el que puede estar un objeto y cada evento que lo lleva a otro. Las transiciones que faltan aparecen en la revisión en lugar de en los tickets de soporte. Este artículo construye uno para una suscripción SaaS, con los estados que documenta Stripe Billing para que puedas comparar el modelo con un sistema real, y explica la notación a medida que aparece.

Cuándo dibujar una máquina de estados

Dibuja una cuando un único objeto tenga un ciclo de vida con reglas: un pedido, una suscripción, un pago, un ticket de soporte, un despliegue. Las señales de alarma son conocidas:

  • Una columna status con más de tres valores y código que la comprueba en muchos sitios.
  • Indicadores booleanos como is_canceled e is_paused que pueden contradecirse.
  • Discusiones sobre si algo "puede ocurrir" desde un estado concreto.

Un diagrama de estados es la imagen equivocada para una conversación entre varios participantes, donde un diagrama de secuencia muestra el orden de los mensajes, y para un proceso de negocio con muchas personas y traspasos, donde encaja mejor un diagrama BPMN.

La notación

Elemento Notación Significado
Estado Rectángulo con esquinas redondeadas Una condición en la que el objeto permanece hasta que llega un evento
Pseudoestado inicial Círculo pequeño relleno Donde empieza la máquina
Estado final Círculo relleno dentro de un anillo La máquina ha terminado
Transición Flecha etiquetada event [guard] / action Se pasa cuando ocurre el evento y la guarda es verdadera
Elección Rombo Las guardas de las flechas salientes deciden el destino
Estado compuesto Un estado que contiene estados Reglas que comparte todo lo que hay dentro
Comportamiento interno entry /, exit /, do / Se ejecuta al entrar, al salir o mientras dura el estado

Cada parte de la etiqueta de una transición es opcional. invoice paid es un evento por sí solo, [setting: unpaid] es una guarda por sí sola y cancel / revoke access es un evento con una acción. La sintaxis y los símbolos vienen de la especificación UML 2.5.1.

Los estados de la suscripción

El ejemplo usa los estados del resumen de suscripciones de Stripe, con pagos automáticos con tarjeta:

Estado Qué significa Acceso
incomplete El primer pago aún no se ha hecho; el cliente tiene 23 horas No
incomplete_expired El primer pago nunca se completó; no se cobra nada No
trialing En periodo de prueba Sí
active Al corriente Sí
past_due El pago de la última factura falló o no se intentó Tú decides
unpaid Los reintentos se agotaron y tu configuración eligió este resultado No
paused La prueba terminó sin método de pago y se eligió pausar No
canceled Terminada; Stripe lo describe como un estado terminal No

Muchos productos mantienen el acceso durante past_due mientras se reintentan los pagos, y este ejemplo también. Escribe esa decisión en el diagrama; es la que la gente olvida.

Cómo construir las transiciones

Toma cada estado y pregúntate qué eventos pueden ocurrir en él.

  1. Inicio. subscribe [trial] lleva a trialing; subscribe [no trial] lleva a incomplete.
  2. Primer pago. Desde incomplete, invoice paid lleva a active. Si pasan 23 horas sin pago, la suscripción pasa a incomplete_expired y Stripe anula la factura. Ese estado es final: para volver a intentarlo, el cliente inicia una suscripción nueva.
  3. Fin de la prueba. trial ends va a una elección. [payment succeeds] lleva a active; [no payment method] lleva a paused en este ejemplo. Stripe te deja elegir qué ocurre en ese caso: crear una factura (la opción predeterminada), cancelar o pausar. Dibuja la configuración que de verdad usas, no las tres.
  4. Renovaciones. Desde active, renewal payment fails lleva a past_due, e invoice paid la devuelve.
  5. Reintentos agotados. Otra elección: según tu configuración, la suscripción pasa a unpaid o canceled, o se queda en past_due. Desde unpaid, pagar la factura la devuelve a active.
  6. Salida. cancel lleva active a canceled. Cancelar al final del periodo no es un estado aparte: la suscripción sigue active con un indicador hasta que termina el periodo y luego pasa a canceled.

Un estado compuesto para el acceso

Aquí, tres estados dan acceso: trialing, active y past_due. Dibujarlos dentro de un único estado compuesto, Access granted, te permite escribir la regla una sola vez: entry / grant access y exit / revoke access. Cualquier transición que salga del compuesto revoca el acceso, empiece en el estado que empiece, así que ningún camino puede olvidarlo. Moverse entre estados dentro del compuesto, por ejemplo de trialing a active, no lo abandona y no ejecuta esas acciones.

Un punto inicial lleva a trialing o a incomplete. Trialing, active y past due están dentro de un marco Access granted. El fin de la prueba pasa por una elección hacia active o paused. Una renovación fallida lleva a past due; sin reintentos, se pasa a unpaid o canceled y luego al final.

15 componentes · 17 conexiones

Abrir en Archboard
Contenido del diagrama
  • Access granted
  • trialing
  • active
  • past_due
  • paused
  • incomplete
  • incomplete_expired
  • unpaid
  • canceled
  • subscribe [trial]
  • subscribe [no trial]
  • invoice paid
  • after 23 h / void invoice
  • trial ends
  • [payment succeeds]
  • [no payment method]
  • resume [payment succeeds]
  • renewal payment fails
  • retries exhausted
  • [setting: unpaid]
  • [setting: cancel]
  • cancel
Una máquina de estados para una suscripción SaaS con los estados que documenta Stripe Billing: la prueba y el primer pago, un estado compuesto para todos los estados que dan acceso, las renovaciones fallidas y las dos formas en que termina una suscripción.

Cómo leerlo:

  • Arriba. El punto inicial se divide según la prueba: trialing dentro del compuesto o incomplete fuera. Desde incomplete, el pago lleva a active, y 23 horas sin pago llevan a incomplete_expired y al estado final de la derecha.
  • En el centro, Access granted. trial ends llega a una elección: active cuando el pago se completa y paused, a la izquierda, cuando no hay método de pago. Una renovación fallida lleva active a past_due, y el pago la devuelve.
  • Abajo. Cuando se agotan los reintentos, una segunda elección envía la suscripción a unpaid o a canceled. unpaid todavía puede volver a active pagando; canceled termina en el estado final.
  • Las conexiones que entran en el marco dan acceso, y las que salen lo revocan.

Del diagrama al código

El diagrama se traslada a una tabla de transiciones. Todo lo que no está en la tabla se rechaza:

type Status = 'incomplete' | 'incomplete_expired' | 'trialing' | 'active'
  | 'past_due' | 'unpaid' | 'paused' | 'canceled';

const transitions: Record<Status, Partial<Record<string, Status>>> = {
  incomplete: { invoice_paid: 'active', expired: 'incomplete_expired' },
  trialing: { trial_ended_paid: 'active', trial_ended_no_method: 'paused' },
  active: { payment_failed: 'past_due', cancel: 'canceled' },
  past_due: { invoice_paid: 'active', retries_exhausted: 'unpaid' },
  unpaid: { invoice_paid: 'active' },
  paused: { resumed: 'active' },
  incomplete_expired: {},
  canceled: {},
};

function next(status: Status, event: string): Status {
  const target = transitions[status][event];
  if (!target) throw new Error(`${event} is not allowed in ${status}`);
  return target;
}

Si los eventos llegan de los webhooks de un proveedor de pagos, no des por hecho el orden. La documentación de webhooks de Stripe dice que no garantiza que los eventos lleguen en el orden en que se generaron. Trata cada evento como un motivo para consultar el estado actual de la suscripción y aplica la transición sobre ese estado.

Errores comunes

  • Eventos que faltan. Para cada estado, comprueba cada evento. "¿Qué pasa si el cliente cancela mientras está en past_due?" es una pregunta que el diagrama debe responder.
  • Indicadores dibujados como estados. Cancelar al final del periodo, un descuento o un número de puestos son propiedades de un estado, no estados.
  • Acciones dibujadas como estados. "Enviar el correo de cobro" es una acción en una transición o un comportamiento entry, no un lugar donde espera la suscripción.
  • Sin estado final. Muestra dónde termina el ciclo de vida, para que nadie escriba código que reviva una suscripción cancelada.
  • Guardas que se solapan o dejan huecos. Las guardas que salen de una elección deben cubrir cada caso exactamente una vez; añade [else] si hace falta.
  • Dos ciclos de vida en un diagrama. La suscripción y sus facturas tienen máquinas de estados separadas. Únelas con eventos en lugar de fusionarlas.

Mantén el diagrama junto al código que lo implementa y revisa ambos en el mismo pull request, como se explica en diagramas de arquitectura que no se quedan obsoletos.

Constrúyelo en Archboard

  1. Inicia sesión con Google o GitHub y crea un diagrama.
  2. Del pack UML, añade un Estado por cada estado de la suscripción.
  3. Añade un Marco del pack Básico llamado Access granted alrededor de trialing, active y past_due.
  4. Añade del pack Básico una Elipse pequeña y rellena para el estado inicial, un Rombo para cada elección y un Icono de círculo con punto para cada estado final.
  5. Conecta los estados con conexiones etiquetadas event [guard] / action.
  6. Añade una Nota UML con las acciones de entrada y salida del estado compuesto.

El ejemplo usa 14 nodos de diagrama, dentro del plan Free. Con un agente de IA conectado por MCP puedes pegar tu enum de estados y dejar que esboce los estados, y después revisar tú cada transición.

Preguntas frecuentes

¿Qué diferencia hay entre un diagrama de estados y un diagrama de flujo? Un diagrama de flujo muestra los pasos de un proceso en orden. Un diagrama de estados muestra las condiciones en las que puede estar un objeto y qué eventos lo mueven entre ellas, así que responde a qué está permitido y no a qué viene después.

¿Cada valor de mi columna de estado debería ser un estado? Cada valor que cambia el comportamiento, sí. Si dos valores se comportan igual en todos los casos, únelos; si un valor esconde dos comportamientos, divídelo.

¿Dónde encajan los webhooks en una máquina de estados? Son eventos. Verifícalos, consulta el estado actual al proveedor y aplica la transición, porque los eventos pueden llegar desordenados o más de una vez.

¿Necesito un estado compuesto? Usa uno cuando varios estados compartan una regla, como el acceso o la facturación. Convierte una regla que repetirías en muchas flechas en una acción de entrada y otra de salida.

¿Cuánto detalle deben tener las etiquetas de transición? Nombra el evento en términos del dominio y añade una guarda solo cuando dos flechas salgan con el mismo evento. Pon en el diagrama las acciones que importan para la corrección, como dar acceso.

Empieza gratis — un puesto, sin tarjeta de crédito.

Artículos relacionados

← Volver al blog

Abre un lienzo en un minuto

Inicia sesión con Google o GitHub. Gratis para un asiento. Mejora el plan cuando se una el equipo.