Modeling an Approval Process

I am looking to design an approval process using axon. Basically, the gist is that you submit an item for approval and you specify and approval path to use. An Approval Path consists of steps where each step has a deadline, the users/roles who are responsible for approving/rejecting the item, and a flag to indicate if any/all approvers on the step are required. I’ve already implemented the approval path part (create/delete, add/remove step) and now I want to model submitting something for approval. I imagine that there will be a command named SubmitItemForApproval(approvalPathId, itemId) which kicks off the process if the item isn’t already going thru some sort of approval process. I’m sure a saga will also be involved because the item has to go thru each step at a time where a rejections causes the saga to end immediately and an accept will put the item thru to the next step until there are no more. I’m looking for some suggestions on how I might go about implementing the approval process itself and maybe even how you might model the creation of the approval path. TIA.

I’m not sure what exactly you are asking about but essentially, what Saga is good for is modeling a process.

If you designed the approval process itself as Aggregate, you may not need Saga as all operations would be on the same Aggregate instance anyway.

Hello Milen,
Just to make sure we’re talking about the same thing… The gist of the process is that I might submit something (eg. a timecard). The Approval Path might consist of my manager, and then their manager, and then, say, the department head. I submit my timecard and now my manager gets some sort of notification that they need to review and then either accept or reject. If it gets rejected, then it’s done. Otherwise, it then repeats the process for the next person in line. Once the department head approves it, then it’s done. I’m looking to get an idea of the “components” and how I might model the process with Axon. This is more of an exercise for me ATM, so I’m just looking for pointers/suggestions at the very least. I think Approval Process itself would indeed be an aggregate and perhaps a Saga is not necessary. Does that help?

Hi Brian,

a little late to the game (I was on holiday), but here are my 2 cents on this.

When reading the first post, the first thing that came to mind was: this is an aggregate. The “approval process” seems mainly about deciding whether the process is completed or additional approvals are required. It doesn’t look like there needs to be a saga in there at all. Maybe only to poke other systems if approval steps need to be coordinated with external systems.

As for the approval process definition, that seems like another component. Probably also an aggregate.

The interesting part is the link between those. When you “submit x for approval,” you’ll need to create an Approval Process aggregate instance that is aware of the actual steps to go through. It doesn’t look nice to have command with that entire process inside of it.
You basically have 2 ways to go about this:

  • Have the command handler (either external or from within the aggregate) query for the current approval process steps and include that in the creation event.
  • Have the “Submit for approval” command handled by the Approval Process Definition, and let that command handler “spawn” new approval aggregates.

Both approaches have their pros and cons.
Approach 1 adds some latency to the creation, and it may feel awkward to query for data from the command model (which is perfectly fine, though). But maybe it’s also awkward to require the entire process flow to be included in the first event. I’ll briefly outline a solution for that below.
Approach 2 adds a little bottleneck in case you need to create a lot of workflow instances simultaneously, as the Definition aggregate will execute these commands simultaneously. It also requires the two aggregates to be part of the same module (deployable), which reduces your location transparency.

Requiring to query data to add that to the creation event for the approval aggregate may be awkward. One way to work around that is to create a projection that we consider part of the command model (and thus completely designed for and deployed with the Approval Process Aggregate). You can then fetch the approval definition from within each command handler separately. Just add a parameter to your command handlers.
Whether that’s more beautiful depends on the use case and requirements. I just wanted to mention that as an option.

Hope this helps.

1 Like