Saltar al contenido
DedicatedPHP Contactar

Cómo diseñar un flujo de aprobación de cambios en un SaaS PHP

Una guía para decidir qué cambios requieren revisión, modelar sus estados y permisos, y aplicarlos con auditoría y control de concurrencia en un SaaS PHP.

Diagrama de un flujo de aprobación de cambios de datos en una aplicación SaaS

Cuando un cambio de configuración o de datos de negocio puede afectar a otros usuarios, una aplicación puede necesitar que una persona lo proponga y otra lo revise antes de hacerlo vigente. Diseñar este proceso como un flujo de aprobación de cambios en SaaS PHP requiere algo más que añadir un botón de «aprobar»: hay que separar la propuesta del dato actual, proteger cada transición y definir qué ocurre si el contexto cambia mientras la solicitud espera.

El objetivo es que el sistema pueda responder, de forma verificable, qué se pidió, quién lo revisó, con qué permisos y si llegó a aplicarse. La solución debe ser proporcional al riesgo: un flujo innecesario añade fricción, mientras que uno insuficiente puede permitir cambios incorrectos o difíciles de rastrear.

Decidir qué cambios requieren aprobación

Decidir qué cambios requieren aprobación — guía visual de DedicatedPHP

Empieza clasificando los cambios por impacto, alcance y capacidad de corrección. No todo dato editable necesita revisión. Un usuario que modifica una preferencia personal de bajo impacto puede guardar el cambio directamente. En cambio, podría ser razonable exigir aprobación para alterar una regla de facturación, una configuración compartida por una organización o un dato maestro que afecte a varios procesos.

Define criterios de producto explícitos. Por ejemplo, pregunta si el cambio afecta a más usuarios que quien lo propone, si puede modificar importes o permisos, si requiere una segunda persona por política interna y cuánto costaría corregirlo. Documenta también las excepciones y quién puede modificarlas. Evita convertir la aprobación en un mecanismo general para operaciones que no guardan relación con el caso: el alcance aquí son cambios de configuración o datos de negocio.

La decisión tiene que reflejarse en el servidor, no sólo en la interfaz. Ocultar un botón no impide que alguien invoque directamente un endpoint. La API debe determinar si el tipo de cambio necesita aprobación y aplicar la regla tanto a las operaciones individuales como a las acciones masivas o las integraciones que puedan cambiar el mismo dato.

Separar solicitud y dato vigente

No sobrescribas el dato vigente al crear una propuesta. Guarda una solicitud independiente con, como mínimo, la organización, el recurso afectado, los valores propuestos, el estado, quién la creó y cuándo. Según el producto, también puede ser necesario guardar un motivo, el origen de la solicitud, una fecha límite o una versión del dato original.

Para representar los valores, puedes guardar campos tipados o una estructura serializada validada por el servidor. En ambos casos, evita aceptar una carga arbitraria como si fuera una actualización directa. Valida el esquema, los campos permitidos, los formatos y las reglas de negocio al recibir la propuesta. Vuelve a validar lo que corresponda al aplicarla, porque las condiciones pueden haber cambiado mientras esperaba.

Este diseño hace posible comparar el valor vigente con el propuesto sin alterar la experiencia de otros usuarios. También permite que la pantalla de revisión muestre una diferencia comprensible. No presentes como vigente un valor que sólo está pendiente; deja claro cuál es el dato aplicado y cuál es la propuesta.

Modelar estados y transiciones explícitas

Define un conjunto pequeño de estados con significados precisos. Una secuencia habitual puede incluir proposed (propuesta), in_review (en revisión), approved (aprobada), rejected (rechazada), expired (vencida) y applied (aplicada). No todos los productos necesitan el estado de revisión: si basta con una decisión inmediata, puede omitirse. Lo importante es que cada estado describa una situación operativa y no sea una etiqueta decorativa.

Especifica las transiciones válidas. Por ejemplo, una propuesta puede pasar a revisión o ser rechazada; una solicitud en revisión puede aprobarse o rechazarse; una aprobación puede aplicarse si sigue vigente. Una solicitud vencida no debería aprobarse con el mismo camino que una activa. Las acciones no permitidas deben fallar con una respuesta consistente, aunque la interfaz no ofrezca esa opción.

«Aprobada» y «aplicada» no son equivalentes. La aprobación registra una decisión; la aplicación modifica el dato vigente. Mantener ambas etapas permite detectar fallos de aplicación y mostrar solicitudes aprobadas que aún necesitan atención. Si el proceso puede completarse dentro de una única transacción corta, la decisión y la escritura pueden coordinarse, pero el modelo debe seguir distinguiendo qué ocurrió.

Verificar permisos en cada transición

Autoriza cada acción en el servidor según la organización, el rol, el recurso y el estado actual. No asumas que haber podido crear una solicitud concede permiso para aprobarla o aplicarla. Tampoco confíes en el identificador de organización enviado por el cliente: resuelve el ámbito desde una sesión o credencial validada y comprueba que la solicitud y el recurso pertenecen a ese mismo ámbito.

Si se prohíbe la autoaprobación, comprueba que la identidad de quien aprueba es distinta de la de quien propuso. Esta regla debe ejecutarse en la transición, no sólo en la vista. Define además qué ocurre con las solicitudes de administradores, usuarios de servicio y procesos automatizados; las excepciones requieren una política deliberada, no una omisión accidental.

Una aprobación debería quedar vinculada a una propuesta concreta. Si cambia su contenido, la aprobación anterior deja de ser válida: crea una nueva versión de la solicitud o vuelve a un estado que requiera revisión. Cambiar silenciosamente los valores después de aprobarlos rompe la correspondencia entre lo revisado y lo aplicado.

Gestionar concurrencia, expiración y aplicación

Mientras una solicitud espera, otro actor podría modificar el dato original. Para detectar esa situación, registra la versión del recurso o los valores relevantes cuando se crea la propuesta. Al aplicar, compara la versión esperada con la vigente. Si no coincide, no sobrescribas el cambio nuevo sin criterio: bloquea la aplicación, marca un conflicto o pide una nueva revisión según las reglas del producto.

En una base de datos relacional, una transacción puede proteger la lectura de la solicitud, la comprobación de su estado y la actualización del recurso. El patrón concreto depende del motor y del nivel de concurrencia; un bloqueo pesimista o una actualización condicional por versión pueden ser apropiados. En cualquier caso, la transición debe ser atómica: dos solicitudes simultáneas no deberían aplicar dos veces el mismo cambio.

Haz que la aplicación sea idempotente o que rechace de forma segura los reintentos. Si se actualizan datos en la base de datos y además se envía una notificación o se publica un evento, considera registrar el evento pendiente en la misma transacción y procesarlo después. Así se reduce el riesgo de mostrar una notificación de éxito para una escritura que no se confirmó.

Define también una política de expiración: cuánto tiempo puede permanecer activa una propuesta, qué la vence y si se puede renovar. La expiración debe comprobarse en el servidor al aprobar y aplicar; no basta con cambiar el estado mediante una tarea programada. Si una demora hace que los valores o las condiciones ya no sean fiables, exige una nueva propuesta.

Auditar y operar el flujo

Conserva un registro de quién propuso, aprobó, rechazó y aplicó cada cambio, con fechas, identificadores de organización y recurso, resultado y contexto necesario para una investigación. Guarda una referencia a la versión propuesta y a la decisión. El registro de auditoría no debería poder alterarse desde las funciones normales de edición de solicitudes. Limita los datos registrados a los necesarios y aplica las políticas de acceso y conservación del producto.

La interfaz operativa debe ayudar a encontrar solicitudes pendientes, vencidas, bloqueadas por conflictos o aprobadas pero no aplicadas. Explica el motivo del bloqueo y ofrece un camino seguro para resolverlo; no conviertas un error de aplicación en una aprobación automática. Las notificaciones pueden avisar de nuevas tareas y decisiones, pero son una ayuda: el estado persistido y consultable es la fuente de verdad.

Probar invariantes, permisos y fallos

Probar invariantes, permisos y fallos — guía visual de DedicatedPHP

Las pruebas deben comprobar las reglas que nunca pueden romperse. Una solicitud no aprobada no modifica el dato vigente; una persona sin acceso a la organización no puede leerla ni transicionarla; la autoaprobación falla si está prohibida; y una solicitud aprobada no puede aplicarse con contenido diferente del revisado. Añade pruebas para estados terminales, solicitudes vencidas y transiciones inválidas.

Prueba también carreras entre dos aprobaciones o entre una aprobación y una edición del dato original. Simula fallos durante la aplicación y verifica que la solicitud no quede marcada como aplicada si la escritura no se confirmó. Si existe una tarea que vence solicitudes, comprueba que su ejecución repetida sea segura. Estas pruebas convierten las reglas de negocio en garantías verificables y ayudan a mantener el flujo cuando cambian los permisos o el modelo de datos.

Como criterio de diseño, cada etapa debe tener un responsable, una condición verificable y un resultado observable. Si el equipo no puede explicar quién tiene permiso para cada transición, qué ocurre ante un cambio concurrente o cómo se reconstruye una decisión, el flujo aún necesita definición antes de llegar a producción.

¿Quieres aplicar estas ideas a tu proyecto?Hablemos de tu plataforma PHP.
Ver servicio relacionado