You may want to bulid a state machine that can accept triggers from the users. Nicholas Blumhardt has a really great, lightweight state machine implementation called stateless. You can create a state machine with a simple statement:
var stateMachine = new StateMachine<TState, TTrigger>();
From the project site:
var phoneCall = new StateMachine<State, Trigger>(State.OffHook);
phoneCall.Configure(State.OffHook)
.Permit(Trigger.CallDialed, State.Ringing);
phoneCall.Configure(State.Ringing)
.Permit(Trigger.HungUp, State.OffHook)
.Permit(Trigger.CallConnected, State.Connected);
phoneCall.Configure(State.Connected)
.OnEntry(() => StartCallTimer())
.OnExit(() => StopCallTimer())
.Permit(Trigger.LeftMessage, State.OffHook)
.Permit(Trigger.HungUp, State.OffHook)
.Permit(Trigger.PlacedOnHold, State.OnHold);
// ...
phoneCall.Fire(Trigger.CallDialled);
Assert.AreEqual(State.Ringing, phoneCall.State);
As you can see the code is pretty straight forward. You can accomplish all that you need with a single project.
Since the State and Trigger can be of any type, you can feed the state machine from a database, maybe a Step table, and allow for the triggers of Approve=1, Reject=2. You could create a series of steps ahead of time with the users and allow them to select the triggers by presenting with a step, then allowing them to assign the next step based on the trigger they pick.