Repository: pbinitiative/zenbpm
Pull request #45: Feature/15 bpmn model restruct
Author: login: dmytro-gundartsev
Labels: name: bpmn engine
Created: 2025-03-05T12:30:41Z | Merged: 2025-03-07T11:28:07Z

### Motivation/Abstract
Brining the basic BPMN structures into correspondence to the BPMN 2.0 spec

### Description/Comments
Restructured Core and Process elements with changed hierarchically embedded structures.

Brining the 

### Checklist

Depending on your PR, please ensure the overall consistency/integrity of the project remains.
Please tick just one check item per section below

#### Tests
- Refactoring is supposed to keep existing tests green




Diff:
diff --git a/pkg/bpmn/activity.go b/pkg/bpmn/activity.go
index ddf429c8..9422bc44 100644
--- a/pkg/bpmn/activity.go
+++ b/pkg/bpmn/activity.go
@@ -43,13 +43,13 @@ const (
 type activity interface {
 	Key() int64
 	State() ActivityState
-	Element() *bpmn20.BaseElement
+	Element() bpmn20.FlowNode
 }
 
 type elementActivity struct {
 	key     int64         `json:"k"`
 	state   ActivityState `json:"s"`
-	element *bpmn20.BaseElement
+	element bpmn20.FlowNode
 }
 
 func (a elementActivity) Key() int64 {
@@ -60,7 +60,7 @@ func (a elementActivity) State() ActivityState {
 	return a.state
 }
 
-func (a elementActivity) Element() *bpmn20.BaseElement {
+func (a elementActivity) Element() bpmn20.FlowNode {
 	return a.element
 }
 
@@ -69,7 +69,7 @@ func (a elementActivity) Element() *bpmn20.BaseElement {
 type gatewayActivity struct {
 	key                     int64         `json:"k"`
 	state                   ActivityState `json:"s"`
-	element                 *bpmn20.BaseElement
+	element                 bpmn20.FlowNode
 	parallel                bool
 	inboundFlowIdsCompleted []string
 }
@@ -82,12 +82,12 @@ func (ga *gatewayActivity) State() ActivityState {
 	return ga.state
 }
 
-func (ga *gatewayActivity) Element() *bpmn20.BaseElement {
+func (ga *gatewayActivity) Element() bpmn20.FlowNode {
 	return ga.element
 }
 
 func (ga *gatewayActivity) AreInboundFlowsCompleted() bool {
-	for _, association := range (*ga.element).GetIncomingAssociation() {
+	for _, association := range ga.element.GetIncomingAssociation() {
 		if !contains(ga.inboundFlowIdsCompleted, association) {
 			return false
 		}
@@ -114,7 +114,7 @@ func (ga gatewayActivity) MarshalJSON() ([]byte, error) {
 	}{
 		Key:                     ga.key,
 		State:                   ga.state,
-		ElementID:               (*ga.element).GetId(), // Get the ID from the element
+		ElementID:               ga.element.GetId(), // Get the ID from the element
 		Parallel:                ga.parallel,
 		InboundFlowIdsCompleted: ga.inboundFlowIdsCompleted,
 	})
@@ -125,26 +125,26 @@ func (ga gatewayActivity) MarshalJSON() ([]byte, error) {
 type eventBasedGatewayActivity struct {
 	key                       int64
 	state                     ActivityState
-	element                   *bpmn20.BaseElement
+	element                   bpmn20.FlowNode
 	OutboundActivityCompleted string
 }
 
-func (ebg *eventBasedGatewayActivity) Key() int64 {
+func (ebg eventBasedGatewayActivity) Key() int64 {
 	return ebg.key
 }
 
-func (ebg *eventBasedGatewayActivity) State() ActivityState {
+func (ebg eventBasedGatewayActivity) State() ActivityState {
 	return ebg.state
 }
 
-func (ebg *eventBasedGatewayActivity) Element() *bpmn20.BaseElement {
+func (ebg eventBasedGatewayActivity) Element() bpmn20.FlowNode {
 	return ebg.element
 }
 
-func (ebg *eventBasedGatewayActivity) SetOutboundCompleted(id string) {
+func (ebg eventBasedGatewayActivity) SetOutboundCompleted(id string) {
 	ebg.OutboundActivityCompleted = id
 }
 
-func (ebg *eventBasedGatewayActivity) OutboundCompleted() bool {
+func (ebg eventBasedGatewayActivity) OutboundCompleted() bool {
 	return len(ebg.OutboundActivityCompleted) > 0
 }
diff --git a/pkg/bpmn/command.go b/pkg/bpmn/command.go
index af5ffe7e..efdb1f06 100644
--- a/pkg/bpmn/command.go
+++ b/pkg/bpmn/command.go
@@ -32,7 +32,7 @@ func (f flowTransitionCommand) Type() commandType {
 
 type activityCommand struct {
 	sourceId       string
-	element        *bpmn20.BaseElement
+	element        bpmn20.FlowNode
 	originActivity activity
 }
 
diff --git a/pkg/bpmn/conditions_test.go b/pkg/bpmn/conditions_test.go
index f5ce8b7f..433e2db3 100644
--- a/pkg/bpmn/conditions_test.go
+++ b/pkg/bpmn/conditions_test.go
@@ -193,7 +193,7 @@ func Test_evaluation_error_percolates_up(t *testing.T) {
 	// then
 	then.AssertThat(t, instance.State, is.EqualTo(Failed))
 	then.AssertThat(t, err, is.Not(is.Nil()))
-	then.AssertThat(t, err.Error(), has.Prefix("Error evaluating expression in flow element id="))
+	then.AssertThat(t, err.Error(), has.Prefix("Error evaluating expression in flow activity id="))
 
 	// cleanup
 	bpmnEngine.Stop()
diff --git a/pkg/bpmn/engine.go b/pkg/bpmn/engine.go
index 8854493c..158d5cc0 100644
--- a/pkg/bpmn/engine.go
+++ b/pkg/bpmn/engine.go
@@ -143,9 +143,9 @@ func (state *BpmnEngineState) run(instance *processInstanceInfo) (err error) {
 	case Ready:
 		// use start events to start the instance
 		for _, startEvent := range process.definitions.Process.StartEvents {
-			var be bpmn20.BaseElement = startEvent
+			var be bpmn20.FlowNode = startEvent
 			commandQueue = append(commandQueue, activityCommand{
-				element: &be,
+				element: be,
 			})
 		}
 		instance.State = Active
@@ -183,7 +183,7 @@ func (state *BpmnEngineState) run(instance *processInstanceInfo) (err error) {
 			sourceActivity := cmd.(flowTransitionCommand).sourceActivity
 			flowId := cmd.(flowTransitionCommand).sequenceFlowId
 			nextFlows := bpmn20.FindSequenceFlows(&process.definitions.Process.SequenceFlows, []string{flowId})
-			if bpmn20.ExclusiveGateway == (*sourceActivity.Element()).GetType() {
+			if bpmn20.ExclusiveGateway == sourceActivity.Element().GetType() {
 				nextFlows, err = exclusivelyFilterByConditionExpression(nextFlows, instance.VariableHolder.Variables())
 				if err != nil {
 					instance.State = Failed
@@ -192,7 +192,7 @@ func (state *BpmnEngineState) run(instance *processInstanceInfo) (err error) {
 			}
 			for _, flow := range nextFlows {
 				state.exportSequenceFlowEvent(*process, *instance, flow)
-				baseElements := bpmn20.FindBaseElementsById(&process.definitions, flow.TargetRef)
+				baseElements := bpmn20.FindFlowNodesById(&process.definitions, flow.TargetRef)
 				targetBaseElement := baseElements[0]
 				aCmd := activityCommand{
 					sourceId:       flowId,
@@ -233,13 +233,13 @@ func (state *BpmnEngineState) run(instance *processInstanceInfo) (err error) {
 	return err
 }
 
-func (state *BpmnEngineState) handleElement(process *ProcessInfo, instance *processInstanceInfo, element *bpmn20.BaseElement, originActivity activity) []command {
-	state.exportElementEvent(*process, *instance, *element, exporter.ElementActivated) // FIXME: don't create event on continuation ?!?!
+func (state *BpmnEngineState) handleElement(process *ProcessInfo, instance *processInstanceInfo, element bpmn20.FlowNode, originActivity activity) []command {
+	state.exportElementEvent(*process, *instance, element, exporter.ElementActivated) // FIXME: don't create event on continuation ?!?!
 	createFlowTransitions := true
 	var activity activity
 	var nextCommands []command
 	var err error
-	switch (*element).GetType() {
+	switch element.GetType() {
 	case bpmn20.StartEvent:
 		createFlowTransitions = true
 		activity = &elementActivity{
@@ -249,7 +249,7 @@ func (state *BpmnEngineState) handleElement(process *ProcessInfo, instance *proc
 		}
 	case bpmn20.EndEvent:
 		state.handleEndEvent(process, instance)
-		state.exportElementEvent(*process, *instance, *element, exporter.ElementCompleted) // special case here, to end the instance
+		state.exportElementEvent(*process, *instance, element, exporter.ElementCompleted) // special case here, to end the instance
 		createFlowTransitions = false
 		activity = &elementActivity{
 			key:     state.generateKey(),
@@ -257,44 +257,44 @@ func (state *BpmnEngineState) handleElement(process *ProcessInfo, instance *proc
 			element: element,
 		}
 	case bpmn20.ServiceTask:
-		taskElement := (*element).(bpmn20.TaskElement)
-		_, activity = state.handleServiceTask(process, instance, &taskElement)
+		taskElement := element.(bpmn20.TaskElement)
+		_, activity = state.handleServiceTask(process, instance, taskElement)
 		createFlowTransitions = activity.State() == Completed
 	case bpmn20.UserTask:
-		taskElement := (*element).(bpmn20.TaskElement)
-		activity = state.handleUserTask(process, instance, &taskElement)
+		taskElement := element.(bpmn20.TaskElement)
+		activity = state.handleUserTask(process, instance, taskElement)
 		createFlowTransitions = activity.State() == Completed
 	case bpmn20.IntermediateCatchEvent:
-		ice := (*element).(bpmn20.TIntermediateCatchEvent)
+		ice := element.(bpmn20.TIntermediateCatchEvent)
 		createFlowTransitions, activity, err = state.handleIntermediateCatchEvent(process, instance, ice, originActivity)
 		if err != nil {
 			nextCommands = append(nextCommands, errorCommand{
 				err:         err,
-				elementId:   (*element).GetId(),
-				elementName: (*element).GetName(),
+				elementId:   element.GetId(),
+				elementName: element.GetName(),
 			})
 		} else {
 			nextCommands = append(nextCommands, createCheckExclusiveGatewayDoneCommand(originActivity)...)
 		}
 
-		ms, err := activity.(*MessageSubscription)
+		ms, err := activity.(MessageSubscription)
 		if !err {
 			// Handle the case when activity is not a MessageSubscription
 			// For example, you can return an error or log a message
 			log.Panicf("Unexpected activity type: %T", activity)
 		}
-		state.persistence.PersistNewMessageSubscription(ms)
+		state.persistence.PersistNewMessageSubscription(&ms)
 	case bpmn20.IntermediateThrowEvent:
 		activity = &elementActivity{
 			key:     state.generateKey(),
 			state:   Active, // FIXME: should be Completed?
 			element: element,
 		}
-		cmds := state.handleIntermediateThrowEvent(process, instance, (*element).(bpmn20.TIntermediateThrowEvent), activity)
+		cmds := state.handleIntermediateThrowEvent(process, instance, element.(bpmn20.TIntermediateThrowEvent), activity)
 		nextCommands = append(nextCommands, cmds...)
 		createFlowTransitions = false
 	case bpmn20.ParallelGateway:
-		createFlowTransitions, activity = state.handleParallelGateway(process, instance, (*element).(bpmn20.TParallelGateway), originActivity)
+		createFlowTransitions, activity = state.handleParallelGateway(process, instance, element.(bpmn20.TParallelGateway), originActivity)
 	case bpmn20.ExclusiveGateway:
 		activity = elementActivity{
 			key:     state.generateKey(),
@@ -318,17 +318,17 @@ func (state *BpmnEngineState) handleElement(process *ProcessInfo, instance *proc
 		}
 		createFlowTransitions = true
 	default:
-		panic(fmt.Sprintf("[invariant check] unsupported element: id=%s, type=%s", (*element).GetId(), (*element).GetType()))
+		panic(fmt.Sprintf("[invariant check] unsupported element: id=%s, type=%s", element.GetId(), element.GetType()))
 	}
 	if createFlowTransitions && err == nil {
-		state.exportElementEvent(*process, *instance, *element, exporter.ElementCompleted)
+		state.exportElementEvent(*process, *instance, element, exporter.ElementCompleted)
 		nextCommands = append(nextCommands, createNextCommands(process, instance, element, activity)...)
 	}
 	return nextCommands
 }
 
 func createCheckExclusiveGatewayDoneCommand(originActivity activity) (cmds []command) {
-	if (*originActivity.Element()).GetType() == bpmn20.EventBasedGateway {
+	if originActivity.Element().GetType() == bpmn20.EventBasedGateway {
 		evtBasedGatewayActivity := originActivity.(*eventBasedGatewayActivity)
 		cmds = append(cmds, checkExclusiveGatewayDoneCommand{
 			gatewayActivity: *evtBasedGatewayActivity,
@@ -337,18 +337,18 @@ func createCheckExclusiveGatewayDoneCommand(originActivity activity) (cmds []com
 	return cmds
 }
 
-func createNextCommands(process *ProcessInfo, instance *processInstanceInfo, element *bpmn20.BaseElement, activity activity) (cmds []command) {
-	nextFlows := bpmn20.FindSequenceFlows(&process.definitions.Process.SequenceFlows, (*element).GetOutgoingAssociation())
+func createNextCommands(process *ProcessInfo, instance *processInstanceInfo, element bpmn20.FlowNode, activity activity) (cmds []command) {
+	nextFlows := bpmn20.FindSequenceFlows(&process.definitions.Process.SequenceFlows, element.GetOutgoingAssociation())
 	var err error
-	switch (*element).GetType() {
+	switch element.GetType() {
 	case bpmn20.ExclusiveGateway:
 		nextFlows, err = exclusivelyFilterByConditionExpression(nextFlows, instance.VariableHolder.Variables())
 		if err != nil {
 			instance.State = Failed
 			cmds = append(cmds, errorCommand{
 				err:         err,
-				elementId:   (*element).GetId(),
-				elementName: (*element).GetName(),
+				elementId:   element.GetId(),
+				elementName: element.GetName(),
 			})
 			return cmds
 		}
@@ -358,8 +358,8 @@ func createNextCommands(process *ProcessInfo, instance *processInstanceInfo, ele
 			instance.State = Failed
 			return []command{
 				errorCommand{
-					elementId:   (*element).GetId(),
-					elementName: (*element).GetName(),
+					elementId:   element.GetId(),
+					elementName: element.GetName(),
 					err:         err,
 				},
 			}
@@ -367,7 +367,7 @@ func createNextCommands(process *ProcessInfo, instance *processInstanceInfo, ele
 	}
 	for _, flow := range nextFlows {
 		cmds = append(cmds, flowTransitionCommand{
-			sourceId:       (*element).GetId(),
+			sourceId:       element.GetId(),
 			sourceActivity: activity,
 			sequenceFlowId: flow.Id,
 		})
@@ -382,13 +382,13 @@ func (state *BpmnEngineState) handleIntermediateCatchEvent(process *ProcessInfo,
 	} else if ice.TimerEventDefinition.Id != "" {
 		continueFlow, activity, err = state.handleIntermediateTimerCatchEvent(instance, ice, originActivity)
 	} else if ice.LinkEventDefinition.Id != "" {
-		var be bpmn20.BaseElement = ice
+		var be bpmn20.FlowNode = ice
 		activity = &elementActivity{
 			key:     state.generateKey(),
 			state:   Active, // FIXME: should be Completed?
-			element: &be,
+			element: be,
 		}
-		throwLinkName := (*originActivity.Element()).(bpmn20.TIntermediateThrowEvent).LinkEventDefinition.Name
+		throwLinkName := originActivity.Element().(bpmn20.TIntermediateThrowEvent).LinkEventDefinition.Name
 		catchLinkName := ice.LinkEventDefinition.Name
 		elementVarHolder := var_holder.New(&instance.VariableHolder, nil)
 		if err := propagateProcessInstanceVariables(&elementVarHolder, ice.Output); err != nil {
@@ -419,16 +419,16 @@ func (state *BpmnEngineState) handleEndEvent(process *ProcessInfo, instance *pro
 func (state *BpmnEngineState) handleParallelGateway(process *ProcessInfo, instance *processInstanceInfo, element bpmn20.TParallelGateway, originActivity activity) (continueFlow bool, resultActivity activity) {
 	resultActivity = instance.findActiveActivityByElementId(element.Id)
 	if resultActivity == nil {
-		var be bpmn20.BaseElement = element
+		var be bpmn20.FlowNode = element
 		resultActivity = &gatewayActivity{
 			key:      state.generateKey(),
 			state:    Active,
-			element:  &be,
+			element:  be,
 			parallel: true,
 		}
 		instance.appendActivity(resultActivity)
 	}
-	sourceFlow := bpmn20.FindFirstSequenceFlow(&process.definitions.Process.SequenceFlows, (*originActivity.Element()).GetId(), element.GetId())
+	sourceFlow := bpmn20.FindFirstSequenceFlow(&process.definitions.Process.SequenceFlows, originActivity.Element().GetId(), element.GetId())
 	resultActivity.(*gatewayActivity).SetInboundFlowCompleted(sourceFlow.Id)
 	continueFlow = resultActivity.(*gatewayActivity).parallel && resultActivity.(*gatewayActivity).AreInboundFlowsCompleted()
 	if continueFlow {
@@ -446,7 +446,7 @@ func (state *BpmnEngineState) findActiveJobsForContinuation(instance *processIns
 // if no ids are provided, all active subscriptions are returned
 func (state *BpmnEngineState) findActiveSubscriptions(instance *processInstanceInfo) (result []*MessageSubscription) {
 	for _, ms := range state.persistence.FindMessageSubscription(-1, instance, "", Active) {
-		bes := bpmn20.FindBaseElementsById(&instance.ProcessInfo.definitions, ms.ElementId)
+		bes := bpmn20.FindFlowNodesById(&instance.ProcessInfo.definitions, ms.ElementId)
 		if len(bes) == 0 {
 			continue
 		}
@@ -461,7 +461,7 @@ func (state *BpmnEngineState) findActiveSubscriptions(instance *processInstanceI
 // findCreatedTimers the list of all scheduled/creates timers in the engine, not yet completed
 func (state *BpmnEngineState) findCreatedTimers(instance *processInstanceInfo) (result []*Timer) {
 	for _, t := range state.persistence.FindTimers(-1, instance.InstanceKey, TimerCreated) {
-		bes := bpmn20.FindBaseElementsById(&instance.ProcessInfo.definitions, t.ElementId)
+		bes := bpmn20.FindFlowNodesById(&instance.ProcessInfo.definitions, t.ElementId)
 		if len(bes) == 0 {
 			continue
 		}
diff --git a/pkg/bpmn/events.go b/pkg/bpmn/events.go
index 6c43a987..c9253f7f 100644
--- a/pkg/bpmn/events.go
+++ b/pkg/bpmn/events.go
@@ -16,7 +16,7 @@ type MessageSubscription struct {
 	MessageState       ActivityState `json:"s"`
 	CreatedAt          time.Time     `json:"c"`
 	originActivity     activity
-	baseElement        *bpmn20.BaseElement
+	baseElement        bpmn20.FlowNode
 }
 
 func (m MessageSubscription) Key() int64 {
@@ -27,7 +27,7 @@ func (m MessageSubscription) State() ActivityState {
 	return m.MessageState
 }
 
-func (m MessageSubscription) Element() *bpmn20.BaseElement {
+func (m MessageSubscription) Element() bpmn20.FlowNode {
 	return m.baseElement
 }
 
@@ -83,7 +83,7 @@ func (state *BpmnEngineState) GetTimersScheduled() []Timer {
 func (state *BpmnEngineState) handleIntermediateMessageCatchEvent(process *ProcessInfo, instance *processInstanceInfo, ice bpmn20.TIntermediateCatchEvent, originActivity activity) (continueFlow bool, ms *MessageSubscription, err error) {
 	ms = findMatchingActiveSubscriptions(state, instance, ice.Id)
 
-	if originActivity != nil && (*originActivity.Element()).GetType() == bpmn20.EventBasedGateway {
+	if originActivity != nil && originActivity.Element().GetType() == bpmn20.EventBasedGateway {
 		ebgActivity := originActivity.(*eventBasedGatewayActivity)
 		if ebgActivity.OutboundCompleted() {
 			ms.MessageState = WithDrawn // FIXME: is this correct?
@@ -117,7 +117,7 @@ func (state *BpmnEngineState) handleIntermediateMessageCatchEvent(process *Proce
 		ms.MessageState = Completed
 		if ms.originActivity != nil {
 			originActivity := instance.findActivity(ms.originActivity.Key())
-			if originActivity != nil && (*originActivity.Element()).GetType() == bpmn20.EventBasedGateway {
+			if originActivity != nil && originActivity.Element().GetType() == bpmn20.EventBasedGateway {
 				ebgActivity := originActivity.(*eventBasedGatewayActivity)
 				ebgActivity.SetOutboundCompleted(ice.Id)
 			}
@@ -128,7 +128,7 @@ func (state *BpmnEngineState) handleIntermediateMessageCatchEvent(process *Proce
 }
 
 func (state *BpmnEngineState) createMessageSubscription(instance *processInstanceInfo, ice bpmn20.TIntermediateCatchEvent) *MessageSubscription {
-	var be bpmn20.BaseElement = ice
+	var be bpmn20.FlowNode = ice
 	ms := &MessageSubscription{
 		ElementId:          ice.Id,
 		ElementInstanceKey: state.generateKey(),
@@ -137,7 +137,7 @@ func (state *BpmnEngineState) createMessageSubscription(instance *processInstanc
 		Name:               ice.Name,
 		CreatedAt:          time.Now(),
 		MessageState:       Active,
-		baseElement:        &be,
+		baseElement:        be,
 	}
 	return ms
 }
diff --git a/pkg/bpmn/exporter.go b/pkg/bpmn/exporter.go
index 43b1e810..1f833b14 100644
--- a/pkg/bpmn/exporter.go
+++ b/pkg/bpmn/exporter.go
@@ -48,7 +48,7 @@ func (state *BpmnEngineState) exportProcessInstanceEvent(process ProcessInfo, pr
 	}
 }
 
-func (state *BpmnEngineState) exportElementEvent(process ProcessInfo, processInstance processInstanceInfo, element bpmn20.BaseElement, intent exporter.Intent) {
+func (state *BpmnEngineState) exportElementEvent(process ProcessInfo, processInstance processInstanceInfo, element bpmn20.FlowNode, intent exporter.Intent) {
 	event := exporter.ProcessInstanceEvent{
 		ProcessId:          process.BpmnProcessId,
 		ProcessKey:         process.ProcessKey,
diff --git a/pkg/bpmn/expressions.go b/pkg/bpmn/expressions.go
index 27cd54ee..d12d5a3c 100644
--- a/pkg/bpmn/expressions.go
+++ b/pkg/bpmn/expressions.go
@@ -4,7 +4,7 @@ import (
 	"strings"
 
 	"github.com/antonmedv/expr"
-	"github.com/pbinitiative/zenbpm/pkg/bpmn/model/bpmn20/extensions"
+	"github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
 	"github.com/pbinitiative/zenbpm/pkg/bpmn/var_holder"
 )
 
diff --git a/pkg/bpmn/jobs.go b/pkg/bpmn/jobs.go
index cd84f5a3..bc2a85c5 100644
--- a/pkg/bpmn/jobs.go
+++ b/pkg/bpmn/jobs.go
@@ -15,7 +15,7 @@ type job struct {
 	JobKey             int64         `json:"jk"`
 	JobState           ActivityState `json:"s"`
 	CreatedAt          time.Time     `json:"c"`
-	baseElement        *bpmn20.BaseElement
+	baseElement        bpmn20.FlowNode
 }
 
 func (j job) Key() int64 {
@@ -26,11 +26,11 @@ func (j job) State() ActivityState {
 	return j.JobState
 }
 
-func (j job) Element() *bpmn20.BaseElement {
+func (j job) Element() bpmn20.FlowNode {
 	return j.baseElement
 }
 
-func (state *BpmnEngineState) handleServiceTask(process *ProcessInfo, instance *processInstanceInfo, element *bpmn20.TaskElement) (bool, *job) {
+func (state *BpmnEngineState) handleServiceTask(process *ProcessInfo, instance *processInstanceInfo, element bpmn20.TaskElement) (bool, *job) {
 	job := findOrCreateJob(state, element, instance, state.generateKey)
 
 	//FIXME: logic of using the internal handler needs to be discussed whether it will be kept
@@ -53,7 +53,7 @@ func (state *BpmnEngineState) handleServiceTask(process *ProcessInfo, instance *
 				createdAt:                job.CreatedAt,
 				variableHolder:           variableHolder,
 			}
-			if err := evaluateLocalVariables(&variableHolder, (*element).GetInputMapping()); err != nil {
+			if err := evaluateLocalVariables(&variableHolder, element.GetInputMapping()); err != nil {
 				job.JobState = Failed
 				instance.State = Failed
 				state.persistence.PersistJob(job)
@@ -64,7 +64,7 @@ func (state *BpmnEngineState) handleServiceTask(process *ProcessInfo, instance *
 	}
 
 	if job.JobState == Completing {
-		if err := propagateProcessInstanceVariables(&variableHolder, (*element).GetOutputMapping()); err != nil {
+		if err := propagateProcessInstanceVariables(&variableHolder, element.GetOutputMapping()); err != nil {
 			job.JobState = Failed
 			instance.State = Failed
 		}
@@ -88,11 +88,11 @@ func (state *BpmnEngineState) JobCompleteById(jobId int64) {
 
 }
 
-func findOrCreateJob(state *BpmnEngineState, element *bpmn20.TaskElement, instance *processInstanceInfo, generateKey func() int64) *job {
-	be := (*element).(bpmn20.BaseElement)
+func findOrCreateJob(state *BpmnEngineState, element bpmn20.TaskElement, instance *processInstanceInfo, generateKey func() int64) *job {
+	be := element.(bpmn20.FlowNode)
 	jobs := state.persistence.FindJobs(be.GetId(), instance, -1)
 	if len(jobs) > 0 {
-		jobs[0].baseElement = &be
+		jobs[0].baseElement = be
 		return jobs[0]
 	}
 
@@ -104,7 +104,7 @@ func findOrCreateJob(state *BpmnEngineState, element *bpmn20.TaskElement, instan
 		JobKey:             elementInstanceKey + 1,
 		JobState:           Active,
 		CreatedAt:          time.Now(),
-		baseElement:        &be,
+		baseElement:        be,
 	}
 
 	state.persistence.PersistJob(&job)
diff --git a/pkg/bpmn/links.go b/pkg/bpmn/links.go
index 049fbf57..62a10db4 100644
--- a/pkg/bpmn/links.go
+++ b/pkg/bpmn/links.go
@@ -28,10 +28,10 @@ func (state *BpmnEngineState) handleIntermediateThrowEvent(process *ProcessInfo,
 					elementName: ite.Name,
 				}}
 			} else {
-				var element bpmn20.BaseElement = ice
+				var element bpmn20.FlowNode = ice
 				nextCommands = []command{activityCommand{
 					sourceId:       ice.Id,
-					element:        &element,
+					element:        element,
 					originActivity: activity,
 				}}
 			}
diff --git a/pkg/bpmn/marshalling.go b/pkg/bpmn/marshalling.go
index eaaf0367..42c61c1b 100644
--- a/pkg/bpmn/marshalling.go
+++ b/pkg/bpmn/marshalling.go
@@ -71,7 +71,7 @@ type activitySurrogate struct {
 	ActivityKey        int64         `json:"k"`
 	ActivityState      ActivityState `json:"s"`
 	ElementReferenceId string        `json:"e"`
-	elementReference   *bpmn20.BaseElement
+	elementReference   bpmn20.FlowNode
 }
 
 type baseElementPlaceholder struct {
@@ -81,6 +81,9 @@ type baseElementPlaceholder struct {
 func (b baseElementPlaceholder) GetId() string {
 	return b.id
 }
+func (b baseElementPlaceholder) GetDocumentation() []bpmn20.Documentation {
+	panic("the placeholder does not implement all methods, by intent")
+}
 
 func (b baseElementPlaceholder) GetName() string {
 	panic("the placeholder does not implement all methods, by intent")
@@ -112,7 +115,7 @@ func (a activityPlaceholder) State() ActivityState {
 	panic("the placeholder does not implement all methods, by intent")
 }
 
-func (a activityPlaceholder) Element() *bpmn20.BaseElement {
+func (a activityPlaceholder) Element() bpmn20.FlowNode {
 	panic("the placeholder does not implement all methods, by intent")
 }
 
@@ -126,7 +129,7 @@ func (t *Timer) MarshalJSON() ([]byte, error) {
 	ta.OriginActivitySurrogate = activitySurrogate{
 		ActivityKey:        t.originActivity.Key(),
 		ActivityState:      t.originActivity.State(),
-		ElementReferenceId: (*t.originActivity.Element()).GetId(),
+		ElementReferenceId: t.originActivity.Element().GetId(),
 	}
 	return json.Marshal(ta)
 }
@@ -152,7 +155,7 @@ func (m *MessageSubscription) MarshalJSON() ([]byte, error) {
 	msa.OriginActivitySurrogate = activitySurrogate{
 		ActivityKey:        m.originActivity.Key(),
 		ActivityState:      m.originActivity.State(),
-		ElementReferenceId: (*m.originActivity.Element()).GetId(),
+		ElementReferenceId: m.originActivity.Element().GetId(),
 	}
 	return json.Marshal(msa)
 }
@@ -205,7 +208,7 @@ func createEventBasedGatewayActivityAdapter(ebga *eventBasedGatewayActivity) *ac
 		Type:                      eventBasedGatewayActivityAdapterType,
 		Key:                       ebga.key,
 		State:                     ebga.state,
-		ElementReference:          (*ebga.element).GetId(),
+		ElementReference:          ebga.element.GetId(),
 		OutboundActivityCompleted: ebga.OutboundActivityCompleted,
 	}
 	return aa
@@ -216,7 +219,7 @@ func createGatewayActivityAdapter(ga *gatewayActivity) *activityAdapter {
 		Type:                    gatewayActivityAdapterType,
 		Key:                     ga.key,
 		State:                   ga.state,
-		ElementReference:        (*ga.element).GetId(),
+		ElementReference:        ga.element.GetId(),
 		Parallel:                ga.parallel,
 		InboundFlowIdsCompleted: ga.inboundFlowIdsCompleted,
 	}
@@ -233,7 +236,7 @@ func (a activitySurrogate) State() ActivityState {
 	return a.ActivityState
 }
 
-func (a activitySurrogate) Element() *bpmn20.BaseElement {
+func (a activitySurrogate) Element() bpmn20.FlowNode {
 	return a.elementReference
 }
 
@@ -325,20 +328,20 @@ func recoverProcessInstanceActivitiesPart1(pii *processInstanceInfo, activityAda
 	for _, aa := range activityAdapters {
 		switch aa.Type {
 		case gatewayActivityAdapterType:
-			var elementPlaceholder bpmn20.BaseElement = &baseElementPlaceholder{id: aa.ElementReference}
+			var elementPlaceholder bpmn20.FlowNode = &baseElementPlaceholder{id: aa.ElementReference}
 			pii.activities = append(pii.activities, &gatewayActivity{
 				key:                     aa.Key,
 				state:                   aa.State,
-				element:                 &elementPlaceholder,
+				element:                 elementPlaceholder,
 				parallel:                aa.Parallel,
 				inboundFlowIdsCompleted: aa.InboundFlowIdsCompleted,
 			})
 		case eventBasedGatewayActivityAdapterType:
-			var elementPlaceholder bpmn20.BaseElement = &baseElementPlaceholder{id: aa.ElementReference}
+			var elementPlaceholder bpmn20.FlowNode = baseElementPlaceholder{id: aa.ElementReference}
 			pii.activities = append(pii.activities, &eventBasedGatewayActivity{
 				key:                       aa.Key,
 				state:                     aa.State,
-				element:                   &elementPlaceholder,
+				element:                   elementPlaceholder,
 				OutboundActivityCompleted: aa.OutboundActivityCompleted,
 			})
 		default:
@@ -349,7 +352,7 @@ func recoverProcessInstanceActivitiesPart1(pii *processInstanceInfo, activityAda
 
 func recoverProcessInstanceActivitiesPartWithBaseElements(pii *processInstanceInfo, activityAdapters []*activityAdapter) {
 	for _, aa := range activityAdapters {
-		bes := bpmn20.FindBaseElementsById(&pii.ProcessInfo.definitions, aa.ElementReference)
+		bes := bpmn20.FindFlowNodesById(&pii.ProcessInfo.definitions, aa.ElementReference)
 		if len(bes) == 0 {
 			log.Printf("Could not find base element with id %s", aa.ElementReference)
 			continue
@@ -381,9 +384,9 @@ func recoverProcessInstanceActivitiesPart2(state *BpmnEngineState) {
 	// 	for _, a := range pi.activities {
 	// 		switch activity := a.(type) {
 	// 		case *eventBasedGatewayActivity:
-	// 			activity.element = BPMN20.FindBaseElementsById(&pi.ProcessInfo.definitions, (*a.Element()).GetId())[0]
+	// 			activity.element = BPMN20.FindFlowNodesById(&pi.ProcessInfo.definitions, (*a.Element()).GetId())[0]
 	// 		case *gatewayActivity:
-	// 			activity.element = BPMN20.FindBaseElementsById(&pi.ProcessInfo.definitions, (*a.Element()).GetId())[0]
+	// 			activity.element = BPMN20.FindFlowNodesById(&pi.ProcessInfo.definitions, (*a.Element()).GetId())[0]
 	// 		default:
 	// 			panic(fmt.Sprintf("[invariant check] missing case for activity type=%T", a))
 	// 		}
@@ -418,8 +421,8 @@ func recoverJobs(state *BpmnEngineState) error {
 	// 		}
 	// 	}
 	// 	definitions := pi.ProcessInfo.definitions
-	// 	element := BPMN20.FindBaseElementsById(&definitions, j.ElementId)[0]
-	// 	j.baseElement = element
+	// 	activity := BPMN20.FindFlowNodesById(&definitions, j.ElementId)[0]
+	// 	j.baseElement = activity
 	// }
 	return nil
 }
@@ -433,13 +436,13 @@ func recoverTimers(state *BpmnEngineState) error {
 	// 				"the marshalled JSON was likely corrupt", t.ProcessInstanceKey),
 	// 		}
 	// 	}
-	// 	t.baseElement = BPMN20.FindBaseElementsById(&pi.ProcessInfo.definitions, t.ElementId)[0]
+	// 	t.baseElement = BPMN20.FindFlowNodesById(&pi.ProcessInfo.definitions, t.ElementId)[0]
 	// 	availableOriginActivity := pi.findActivity(t.originActivity.Key())
 	// 	if availableOriginActivity != nil {
 	// 		t.originActivity = availableOriginActivity
 	// 	} else {
 	// 		originActivitySurrogate := t.originActivity.(activitySurrogate)
-	// 		originActivitySurrogate.elementReference = BPMN20.FindBaseElementsById(&pi.ProcessInfo.definitions, originActivitySurrogate.ElementReferenceId)[0]
+	// 		originActivitySurrogate.elementReference = BPMN20.FindFlowNodesById(&pi.ProcessInfo.definitions, originActivitySurrogate.ElementReferenceId)[0]
 	// 		t.originActivity = originActivitySurrogate
 	// 	}
 	// }
@@ -455,13 +458,13 @@ func recoverMessageSubscriptions(state *BpmnEngineState) error {
 	// 				"the marshalled JSON was likely corrupt", ms.ProcessInstanceKey),
 	// 		}
 	// 	}
-	// 	ms.baseElement = BPMN20.FindBaseElementsById(&pi.ProcessInfo.definitions, ms.ElementId)[0]
+	// 	ms.baseElement = BPMN20.FindFlowNodesById(&pi.ProcessInfo.definitions, ms.ElementId)[0]
 	// 	availableOriginActivity := pi.findActivity(ms.originActivity.Key())
 	// 	if availableOriginActivity != nil {
 	// 		ms.originActivity = availableOriginActivity
 	// 	} else {
 	// 		originActivitySurrogate := ms.originActivity.(activitySurrogate)
-	// 		originActivitySurrogate.elementReference = BPMN20.FindBaseElementsById(&pi.ProcessInfo.definitions, originActivitySurrogate.ElementReferenceId)[0]
+	// 		originActivitySurrogate.elementReference = BPMN20.FindFlowNodesById(&pi.ProcessInfo.definitions, originActivitySurrogate.ElementReferenceId)[0]
 	// 		ms.originActivity = originActivitySurrogate
 	// 	}
 	// }
diff --git a/pkg/bpmn/model/bpmn20/bpmn_structs.go b/pkg/bpmn/model/bpmn20/bpmn_structs.go
deleted file mode 100644
index bc322fbf..00000000
--- a/pkg/bpmn/model/bpmn20/bpmn_structs.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package bpmn20
-
-import (
-	"github.com/pbinitiative/zenbpm/pkg/bpmn/model/bpmn20/extensions"
-)
-
-type TDefinitions struct {
-	Id                 string     `xml:"id,attr"`
-	Name               string     `xml:"name,attr"`
-	TargetNamespace    string     `xml:"targetNamespace,attr"`
-	ExpressionLanguage string     `xml:"expressionLanguage,attr"`
-	TypeLanguage       string     `xml:"typeLanguage,attr"`
-	Exporter           string     `xml:"exporter,attr"`
-	ExporterVersion    string     `xml:"exporterVersion,attr"`
-	Process            TProcess   `xml:"process"`
-	Messages           []TMessage `xml:"message"`
-}
-
-type TProcess struct {
-	Id                           string                    `xml:"id,attr"`
-	Name                         string                    `xml:"name,attr"`
-	ProcessType                  string                    `xml:"processType,attr"`
-	IsClosed                     bool                      `xml:"isClosed,attr"`
-	IsExecutable                 bool                      `xml:"isExecutable,attr"`
-	DefinitionalCollaborationRef string                    `xml:"definitionalCollaborationRef,attr"`
-	StartEvents                  []TStartEvent             `xml:"startEvent"`
-	EndEvents                    []TEndEvent               `xml:"endEvent"`
-	SequenceFlows                []TSequenceFlow           `xml:"sequenceFlow"`
-	ServiceTasks                 []TServiceTask            `xml:"serviceTask"`
-	UserTasks                    []TUserTask               `xml:"userTask"`
-	ParallelGateway              []TParallelGateway        `xml:"parallelGateway"`
-	ExclusiveGateway             []TExclusiveGateway       `xml:"exclusiveGateway"`
-	IntermediateCatchEvent       []TIntermediateCatchEvent `xml:"intermediateCatchEvent"`
-	IntermediateTrowEvent        []TIntermediateThrowEvent `xml:"intermediateThrowEvent"`
-	EventBasedGateway            []TEventBasedGateway      `xml:"eventBasedGateway"`
-	InclusiveGateway             []TInclusiveGateway       `xml:"inclusiveGateway"`
-}
-
-type TSequenceFlow struct {
-	Id                  string        `xml:"id,attr"`
-	Name                string        `xml:"name,attr"`
-	SourceRef           string        `xml:"sourceRef,attr"`
-	TargetRef           string        `xml:"targetRef,attr"`
-	ConditionExpression []TExpression `xml:"conditionExpression"`
-}
-
-type TExpression struct {
-	Text string `xml:",innerxml"`
-}
-
-type TStartEvent struct {
-	Id                  string   `xml:"id,attr"`
-	Name                string   `xml:"name,attr"`
-	IsInterrupting      bool     `xml:"isInterrupting,attr"`
-	ParallelMultiple    bool     `xml:"parallelMultiple,attr"`
-	IncomingAssociation []string `xml:"incoming"`
-	OutgoingAssociation []string `xml:"outgoing"`
-}
-
-type TEndEvent struct {
-	Id                  string   `xml:"id,attr"`
-	Name                string   `xml:"name,attr"`
-	IncomingAssociation []string `xml:"incoming"`
-	OutgoingAssociation []string `xml:"outgoing"`
-}
-
-type TServiceTask struct {
-	Id                  string                     `xml:"id,attr"`
-	Name                string                     `xml:"name,attr"`
-	Default             string                     `xml:"default,attr"`
-	CompletionQuantity  int                        `xml:"completionQuantity,attr"`
-	IsForCompensation   bool                       `xml:"isForCompensation,attr"`
-	OperationRef        string                     `xml:"operationRef,attr"`
-	Implementation      string                     `xml:"implementation,attr"`
-	IncomingAssociation []string                   `xml:"incoming"`
-	OutgoingAssociation []string                   `xml:"outgoing"`
-	Input               []extensions.TIoMapping    `xml:"extensionElements>ioMapping>input"`
-	Output              []extensions.TIoMapping    `xml:"extensionElements>ioMapping>output"`
-	TaskDefinition      extensions.TTaskDefinition `xml:"extensionElements>taskDefinition"`
-}
-
-type TUserTask struct {
-	Id                   string                           `xml:"id,attr"`
-	Name                 string                           `xml:"name,attr"`
-	IncomingAssociation  []string                         `xml:"incoming"`
-	OutgoingAssociation  []string                         `xml:"outgoing"`
-	Input                []extensions.TIoMapping          `xml:"extensionElements>ioMapping>input"`
-	Output               []extensions.TIoMapping          `xml:"extensionElements>ioMapping>output"`
-	AssignmentDefinition extensions.TAssignmentDefinition `xml:"extensionElements>assignmentDefinition"`
-}
-
-type TParallelGateway struct {
-	Id                  string   `xml:"id,attr"`
-	Name                string   `xml:"name,attr"`
-	IncomingAssociation []string `xml:"incoming"`
-	OutgoingAssociation []string `xml:"outgoing"`
-}
-
-type TExclusiveGateway struct {
-	Id                  string   `xml:"id,attr"`
-	Name                string   `xml:"name,attr"`
-	IncomingAssociation []string `xml:"incoming"`
-	OutgoingAssociation []string `xml:"outgoing"`
-}
-
-type TIntermediateCatchEvent struct {
-	Id                     string                  `xml:"id,attr"`
-	Name                   string                  `xml:"name,attr"`
-	IncomingAssociation    []string                `xml:"incoming"`
-	OutgoingAssociation    []string                `xml:"outgoing"`
-	MessageEventDefinition TMessageEventDefinition `xml:"messageEventDefinition"`
-	TimerEventDefinition   TTimerEventDefinition   `xml:"timerEventDefinition"`
-	LinkEventDefinition    TLinkEventDefinition    `xml:"linkEventDefinition"`
-	ParallelMultiple       bool                    `xml:"parallelMultiple"`
-	Output                 []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
-}
-
-type TIntermediateThrowEvent struct {
-	Id                  string                  `xml:"id,attr"`
-	Name                string                  `xml:"name,attr"`
-	IncomingAssociation []string                `xml:"incoming"`
-	LinkEventDefinition TLinkEventDefinition    `xml:"linkEventDefinition"`
-	Output              []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
-}
-
-type TEventBasedGateway struct {
-	Id                  string   `xml:"id,attr"`
-	Name                string   `xml:"name,attr"`
-	IncomingAssociation []string `xml:"incoming"`
-	OutgoingAssociation []string `xml:"outgoing"`
-}
-
-type TMessageEventDefinition struct {
-	Id         string `xml:"id,attr"`
-	MessageRef string `xml:"messageRef,attr"`
-}
-
-type TTimerEventDefinition struct {
-	Id           string        `xml:"id,attr"`
-	TimeDuration TTimeDuration `xml:"timeDuration"`
-}
-
-type TLinkEventDefinition struct {
-	Id   string `xml:"id,attr"`
-	Name string `xml:"name,attr"`
-}
-
-type TMessage struct {
-	Id   string `xml:"id,attr"`
-	Name string `xml:"name,attr"`
-}
-
-type TTimeDuration struct {
-	XMLText string `xml:",innerxml"`
-}
-
-type TInclusiveGateway struct {
-	Id                  string   `xml:"id,attr"`
-	Name                string   `xml:"name,attr"`
-	IncomingAssociation []string `xml:"incoming"`
-	OutgoingAssociation []string `xml:"outgoing"`
-}
diff --git a/pkg/bpmn/model/bpmn20/core.go b/pkg/bpmn/model/bpmn20/core.go
new file mode 100644
index 00000000..4611fc54
--- /dev/null
+++ b/pkg/bpmn/model/bpmn20/core.go
@@ -0,0 +1,133 @@
+package bpmn20
+
+// TDocumentation  BPMN elements that inherit from the BaseElement will have the capability,
+// through the TDocumentation element, to have one (1) or more text descriptions
+// of that element.
+type TDocumentation struct {
+	// Text attribute is used to capture the text descriptions of a
+	// BPMN element.
+	Text string `xml:"text,text"`
+
+	// Format attribute identifies the format of the text. It MUST follow
+	// the mime-type format. The default is "text/plain".
+	Format string `xml:"textFormat,attr"`
+}
+
+func (documentation TDocumentation) GetText() string {
+	return documentation.Text
+}
+
+func (documentation TDocumentation) GetFormat() string {
+	return documentation.Format
+}
+
+type TBaseElement struct {
+	// Id attribute is used to uniquely identify BPMN elements. The id is
+	// REQUIRED if this element is referenced or intended to be referenced by
+	// something else. If the element is not currently referenced and is never
+	// intended to be referenced, the id MAY be omitted.
+	Id string `xml:"id,attr"`
+
+	// Documentation attribute is used to annotate the BPMN element, such as descriptions
+	// and other documentation.
+	Documentation []TDocumentation `xml:"documentation"`
+}
+
+func (baseElement TBaseElement) GetId() string {
+	return baseElement.Id
+}
+func (baseElement TBaseElement) GetDocumentation() []Documentation {
+	var docs []Documentation
+	for _, doc := range baseElement.Documentation {
+		docs = append(docs, doc)
+	}
+	return docs
+}
+
+type Documentation interface {
+	GetText() string
+	GetFormat() string
+}
+
+// BaseElement is the abstract super class/interface for most BPMN elements.
+// It provides the attributes id and documentation, which other elements will inherit
+type BaseElement interface {
+	GetId() string
+	GetDocumentation() []Documentation
+}
+
+type TRootElementsContainer struct {
+	Process  TProcess   `xml:"process"`
+	Messages []TMessage `xml:"message"`
+}
+
+type TDefinitions struct {
+	TBaseElement
+	TRootElementsContainer
+	Name               string `xml:"name,attr"`
+	TargetNamespace    string `xml:"targetNamespace,attr"`
+	ExpressionLanguage string `xml:"expressionLanguage,attr"`
+	TypeLanguage       string `xml:"typeLanguage,attr"`
+	Exporter           string `xml:"exporter,attr"`
+	ExporterVersion    string `xml:"exporterVersion,attr"`
+}
+
+type TMessage struct {
+	Id   string `xml:"id,attr"`
+	Name string `xml:"name,attr"`
+}
+
+type TCallableElement struct {
+	TBaseElement
+	Name string `xml:"name,attr"`
+}
+
+type FlowElement interface {
+	BaseElement
+	GetName() string
+	GetType() ElementType
+}
+
+type TFlowElement struct {
+	TBaseElement
+	Name string `xml:"name,attr"`
+}
+
+func (fe TFlowElement) GetName() string {
+	return fe.Name
+}
+
+type TSequenceFlow struct {
+	TFlowElement
+	SourceRef           string        `xml:"sourceRef,attr"`
+	TargetRef           string        `xml:"targetRef,attr"`
+	ConditionExpression []TExpression `xml:"conditionExpression"`
+}
+
+// FlowNode is the abstract super class/interface that provides a single element as the source and target Sequence Flow associations.
+// Central abstraction used by the engine to traverse through the process flows.
+type FlowNode interface {
+	FlowElement
+	GetIncomingAssociation() []string
+	GetOutgoingAssociation() []string
+}
+
+type TFlowNode struct {
+	TFlowElement
+	IncomingAssociation []string `xml:"incoming"`
+	OutgoingAssociation []string `xml:"outgoing"`
+}
+
+func (flowNode TFlowNode) GetIncomingAssociation() []string {
+	return flowNode.IncomingAssociation
+}
+
+func (flowNode TFlowNode) GetOutgoingAssociation() []string {
+	return flowNode.OutgoingAssociation
+}
+
+//type TFlowElementsContainer
+
+type TExpression struct {
+	Text string `xml:",innerxml"`
+}
diff --git a/pkg/bpmn/model/bpmn20/elements.go b/pkg/bpmn/model/bpmn20/elements.go
index 15211fea..1ead7aac 100644
--- a/pkg/bpmn/model/bpmn20/elements.go
+++ b/pkg/bpmn/model/bpmn20/elements.go
@@ -1,6 +1,6 @@
 package bpmn20
 
-import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/bpmn20/extensions"
+import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
 
 type ElementType string
 type GatewayDirection string
@@ -25,16 +25,8 @@ const (
 	Mixed       GatewayDirection = "Mixed"
 )
 
-type BaseElement interface {
-	GetId() string
-	GetName() string
-	GetIncomingAssociation() []string
-	GetOutgoingAssociation() []string
-	GetType() ElementType
-}
-
 type TaskElement interface {
-	BaseElement
+	FlowNode
 	GetInputMapping() []extensions.TIoMapping
 	GetOutputMapping() []extensions.TIoMapping
 	GetTaskDefinitionType() string
@@ -43,7 +35,7 @@ type TaskElement interface {
 }
 
 type GatewayElement interface {
-	BaseElement
+	FlowNode
 	IsParallel() bool
 	IsExclusive() bool
 	IsInclusive() bool
@@ -69,23 +61,23 @@ func (startEvent TStartEvent) GetType() ElementType {
 	return StartEvent
 }
 
-func (endEvent TEndEvent) GetId() string {
-	return endEvent.Id
+func (activity TEndEvent) GetId() string {
+	return activity.Id
 }
 
-func (endEvent TEndEvent) GetName() string {
-	return endEvent.Name
+func (activity TEndEvent) GetName() string {
+	return activity.Name
 }
 
-func (endEvent TEndEvent) GetIncomingAssociation() []string {
-	return endEvent.IncomingAssociation
+func (activity TEndEvent) GetIncomingAssociation() []string {
+	return activity.IncomingAssociation
 }
 
-func (endEvent TEndEvent) GetOutgoingAssociation() []string {
-	return endEvent.OutgoingAssociation
+func (activity TEndEvent) GetOutgoingAssociation() []string {
+	return activity.OutgoingAssociation
 }
 
-func (endEvent TEndEvent) GetType() ElementType {
+func (activity TEndEvent) GetType() ElementType {
 	return EndEvent
 }
 
diff --git a/pkg/bpmn/model/bpmn20/helper.go b/pkg/bpmn/model/bpmn20/helper.go
index bb1f54fb..0b838eee 100644
--- a/pkg/bpmn/model/bpmn20/helper.go
+++ b/pkg/bpmn/model/bpmn20/helper.go
@@ -27,62 +27,62 @@ func FindFirstSequenceFlow(sequenceFlows *[]TSequenceFlow, sourceId string, targ
 	return result
 }
 
-func FindBaseElementsById(definitions *TDefinitions, id string) (elements []*BaseElement) {
-	appender := func(element *BaseElement) {
-		if (*element).GetId() == id {
+func FindFlowNodesById(definitions *TDefinitions, id string) (elements []FlowNode) {
+	appender := func(element FlowNode) {
+		if element.GetId() == id {
 			elements = append(elements, element)
 		}
 	}
 	for _, startEvent := range definitions.Process.StartEvents {
-		var be BaseElement = startEvent
-		appender(&be)
+		var be FlowNode = startEvent
+		appender(be)
 	}
 	for _, endEvent := range definitions.Process.EndEvents {
-		var be BaseElement = endEvent
-		appender(&be)
+		var be FlowNode = endEvent
+		appender(be)
 	}
 	for _, task := range definitions.Process.ServiceTasks {
-		var be BaseElement = task
-		appender(&be)
+		var be FlowNode = task
+		appender(be)
 	}
 	for _, task := range definitions.Process.UserTasks {
-		var be BaseElement = task
-		appender(&be)
+		var be FlowNode = task
+		appender(be)
 	}
 	for _, parallelGateway := range definitions.Process.ParallelGateway {
-		var be BaseElement = parallelGateway
-		appender(&be)
+		var be FlowNode = parallelGateway
+		appender(be)
 	}
 	for _, exclusiveGateway := range definitions.Process.ExclusiveGateway {
-		var be BaseElement = exclusiveGateway
-		appender(&be)
+		var be FlowNode = exclusiveGateway
+		appender(be)
 	}
 	for _, eventBasedGateway := range definitions.Process.EventBasedGateway {
-		var be BaseElement = eventBasedGateway
-		appender(&be)
+		var be FlowNode = eventBasedGateway
+		appender(be)
 	}
 	for _, intermediateCatchEvent := range definitions.Process.IntermediateCatchEvent {
-		var be BaseElement = intermediateCatchEvent
-		appender(&be)
+		var be FlowNode = intermediateCatchEvent
+		appender(be)
 	}
-	for _, intermediateCatchEvent := range definitions.Process.IntermediateTrowEvent {
-		var be BaseElement = intermediateCatchEvent
-		appender(&be)
+	for _, intermediateCatchEvent := range definitions.Process.IntermediateThrowEvent {
+		var be FlowNode = intermediateCatchEvent
+		appender(be)
 	}
 	for _, inclusiveGateway := range definitions.Process.InclusiveGateway {
-		var be BaseElement = inclusiveGateway
-		appender(&be)
+		var be FlowNode = inclusiveGateway
+		appender(be)
 	}
 	return elements
 }
 
 // HasConditionExpression returns true, if there's exactly 1 expression present (as by the spec)
 // and there's some non-whitespace-characters available
-func (flow TSequenceFlow) HasConditionExpression() bool {
-	return len(flow.ConditionExpression) == 1 && len(strings.TrimSpace(flow.GetConditionExpression())) > 0
+func (sequenceFlow TSequenceFlow) HasConditionExpression() bool {
+	return len(sequenceFlow.ConditionExpression) == 1 && len(strings.TrimSpace(sequenceFlow.GetConditionExpression())) > 0
 }
 
 // GetConditionExpression returns the embedded expression. There will be a panic thrown, in case none exists!
-func (flow TSequenceFlow) GetConditionExpression() string {
-	return html.UnescapeString(flow.ConditionExpression[0].Text)
+func (sequenceFlow TSequenceFlow) GetConditionExpression() string {
+	return html.UnescapeString(sequenceFlow.ConditionExpression[0].Text)
 }
diff --git a/pkg/bpmn/model/bpmn20/process.go b/pkg/bpmn/model/bpmn20/process.go
new file mode 100644
index 00000000..859765aa
--- /dev/null
+++ b/pkg/bpmn/model/bpmn20/process.go
@@ -0,0 +1,149 @@
+package bpmn20
+
+import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
+
+type TFlowElementsContainer struct {
+	StartEvents            []TStartEvent             `xml:"startEvent"`
+	EndEvents              []TEndEvent               `xml:"endEvent"`
+	SequenceFlows          []TSequenceFlow           `xml:"sequenceFlow"`
+	ServiceTasks           []TServiceTask            `xml:"serviceTask"`
+	UserTasks              []TUserTask               `xml:"userTask"`
+	ParallelGateway        []TParallelGateway        `xml:"parallelGateway"`
+	ExclusiveGateway       []TExclusiveGateway       `xml:"exclusiveGateway"`
+	IntermediateCatchEvent []TIntermediateCatchEvent `xml:"intermediateCatchEvent"`
+	IntermediateThrowEvent []TIntermediateThrowEvent `xml:"intermediateThrowEvent"`
+	EventBasedGateway      []TEventBasedGateway      `xml:"eventBasedGateway"`
+	InclusiveGateway       []TInclusiveGateway       `xml:"inclusiveGateway"`
+}
+
+type TProcess struct {
+	TCallableElement
+	TFlowElementsContainer
+	ProcessType                  string `xml:"processType,attr"`
+	IsClosed                     bool   `xml:"isClosed,attr"`
+	IsExecutable                 bool   `xml:"isExecutable,attr"`
+	DefinitionalCollaborationRef string `xml:"definitionalCollaborationRef,attr"`
+}
+
+type Activity interface {
+	FlowNode
+	GetCompletionQuantity() int
+	GetIsForCompensation() bool
+	GetStartQuantity() int
+}
+
+type TActivity struct {
+	TFlowNode
+	CompletionQuantity int  `xml:"completionQuantity,attr"`
+	IsForCompensation  bool `xml:"isForCompensation,attr"`
+	StartQuantity      int  `xml:"startQuantity,attr"`
+}
+type TTask struct {
+	TActivity
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Input  []extensions.TIoMapping `xml:"extensionElements>ioMapping>input"`
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TGateway struct {
+	TFlowNode
+	GatewayDirection GatewayDirection `xml:"gatewayDirection,attr"`
+}
+
+type TEvent = TActivity
+
+// TExternallyProcessedTask is to be processed by external Job workers. Is not part of original BPMN Implementation
+// BPMN 2.0 Unorthodox.
+type TExternallyProcessedTask struct {
+	TTask
+	TaskDefinition extensions.TTaskDefinition `xml:"extensionElements>taskDefinition"`
+}
+type TServiceTask struct {
+	TExternallyProcessedTask
+	OperationRef   string `xml:"operationRef,attr"`
+	Implementation string `xml:"implementation,attr"`
+}
+
+type TUserTask struct {
+	TTask
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	AssignmentDefinition extensions.TAssignmentDefinition `xml:"extensionElements>assignmentDefinition"`
+}
+
+type TInclusiveGateway struct {
+	TGateway
+}
+
+type TParallelGateway struct {
+	TGateway
+}
+
+type TExclusiveGateway struct {
+	TGateway
+}
+
+type TEventBasedGateway struct {
+	TGateway
+	Instantiate      bool                  `xml:"instantiate,attr"`
+	EventGatewayType EventBasedGatewayType `xml:"eventGatewayType,attr"`
+}
+type EventBasedGatewayType = string
+
+const (
+	EventBasedGatewayTypeExclusive EventBasedGatewayType = "Exclusive"
+	EventBasedGatewayTypeParallel  EventBasedGatewayType = "Parallel"
+)
+
+type TStartEvent struct {
+	TEvent
+	IsInterrupting   bool `xml:"isInterrupting,attr"`
+	ParallelMultiple bool `xml:"parallelMultiple,attr"`
+}
+
+type TEndEvent = TEvent
+
+type TIntermediateCatchEvent struct {
+	TEvent
+	MessageEventDefinition TMessageEventDefinition `xml:"messageEventDefinition"`
+	TimerEventDefinition   TTimerEventDefinition   `xml:"timerEventDefinition"`
+	LinkEventDefinition    TLinkEventDefinition    `xml:"linkEventDefinition"`
+	ParallelMultiple       bool                    `xml:"parallelMultiple"`
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TIntermediateThrowEvent struct {
+	TEvent
+	LinkEventDefinition TLinkEventDefinition `xml:"linkEventDefinition"`
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TMessageEventDefinition struct {
+	Id         string `xml:"id,attr"`
+	MessageRef string `xml:"messageRef,attr"`
+}
+
+type TTimerEventDefinition struct {
+	Id           string        `xml:"id,attr"`
+	TimeDuration TTimeDuration `xml:"timeDuration"`
+}
+
+type TLinkEventDefinition struct {
+	Id   string `xml:"id,attr"`
+	Name string `xml:"name,attr"`
+}
+
+type TTimeDuration struct {
+	XMLText string `xml:",innerxml"`
+}
+
+func (activity TActivity) GetCompletionQuantity() int {
+	return activity.CompletionQuantity
+}
+func (activity TActivity) GetIsForCompensation() bool {
+	return activity.IsForCompensation
+}
+func (activity TActivity) GetStartQuantity() int {
+	return activity.StartQuantity
+}
diff --git a/pkg/bpmn/model/bpmn20/extensions/assignment_definition.go b/pkg/bpmn/model/extensions/assignment_definition.go
similarity index 100%
rename from pkg/bpmn/model/bpmn20/extensions/assignment_definition.go
rename to pkg/bpmn/model/extensions/assignment_definition.go
diff --git a/pkg/bpmn/model/bpmn20/extensions/io_mapping.go b/pkg/bpmn/model/extensions/io_mapping.go
similarity index 100%
rename from pkg/bpmn/model/bpmn20/extensions/io_mapping.go
rename to pkg/bpmn/model/extensions/io_mapping.go
diff --git a/pkg/bpmn/model/bpmn20/extensions/task_definition.go b/pkg/bpmn/model/extensions/task_definition.go
similarity index 100%
rename from pkg/bpmn/model/bpmn20/extensions/task_definition.go
rename to pkg/bpmn/model/extensions/task_definition.go
diff --git a/pkg/bpmn/process_instance.go b/pkg/bpmn/process_instance.go
index c4a65c3f..654480dd 100644
--- a/pkg/bpmn/process_instance.go
+++ b/pkg/bpmn/process_instance.go
@@ -62,7 +62,7 @@ func (pii *processInstanceInfo) appendActivity(activity activity) {
 
 func (pii *processInstanceInfo) findActiveActivityByElementId(id string) activity {
 	for _, a := range pii.activities {
-		if (*a.Element()).GetId() == id && a.State() == Active {
+		if a.Element().GetId() == id && a.State() == Active {
 			return a
 		}
 	}
diff --git a/pkg/bpmn/rqlite_persistence_facade.go b/pkg/bpmn/rqlite_persistence_facade.go
index 3a8ded48..b22547ef 100644
--- a/pkg/bpmn/rqlite_persistence_facade.go
+++ b/pkg/bpmn/rqlite_persistence_facade.go
@@ -185,7 +185,7 @@ func (persistence *BpmnEnginePersistenceRqlite) FindMessageSubscription(originAc
 			MessageState:       reverseMap(activityStateMap)[subscription.State],
 			CreatedAt:          time.Unix(subscription.CreatedAt, 0),
 			originActivity:     constructOriginActivity(subscription.OriginActivityKey, subscription.OriginActivityState, subscription.OriginActivityId, pi.ProcessInfo),
-			baseElement:        bpmn20.FindBaseElementsById(&pi.ProcessInfo.definitions, subscription.ElementID)[0],
+			baseElement:        bpmn20.FindFlowNodesById(&pi.ProcessInfo.definitions, subscription.ElementID)[0],
 		})
 	}
 	return resultSubscriptions
@@ -196,7 +196,7 @@ func constructOriginActivity(originActivityKey int64, originActivityState int, o
 	activity := &elementActivity{
 		key:     originActivityKey,
 		state:   reverseMap(activityStateMap)[originActivityState],
-		element: bpmn20.FindBaseElementsById(&process.definitions, originActivityId)[0],
+		element: bpmn20.FindFlowNodesById(&process.definitions, originActivityId)[0],
 	}
 
 	return activity
@@ -252,7 +252,7 @@ func (persistence *BpmnEnginePersistenceRqlite) FindJobs(elementId string, proce
 
 		}
 
-		bes := bpmn20.FindBaseElementsById(&processInstance.ProcessInfo.definitions, resultJob.ElementId)
+		bes := bpmn20.FindFlowNodesById(&processInstance.ProcessInfo.definitions, resultJob.ElementId)
 		if len(bes) == 0 {
 			continue
 		}
@@ -345,7 +345,7 @@ func (persistence *BpmnEnginePersistenceRqlite) PersistNewMessageSubscription(su
 	if subscription.originActivity != nil {
 		ms.OriginActivityKey = subscription.originActivity.Key()
 		ms.OriginActivityState = activityStateMap[subscription.originActivity.State()]
-		ms.OriginActivityId = (*subscription.originActivity.Element()).GetId()
+		ms.OriginActivityId = subscription.originActivity.Element().GetId()
 	}
 
 	return persistence.rqlitePersistence.PersistNewMessageSubscription(ms)
diff --git a/pkg/bpmn/task_handler.go b/pkg/bpmn/task_handler.go
index 179f3529..c3018718 100644
--- a/pkg/bpmn/task_handler.go
+++ b/pkg/bpmn/task_handler.go
@@ -2,7 +2,7 @@ package bpmn
 
 import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/bpmn20"
 
-type taskMatcher func(element *bpmn20.TaskElement) bool
+type taskMatcher func(element bpmn20.TaskElement) bool
 
 type taskHandlerType string
 
@@ -62,8 +62,8 @@ func (state *BpmnEngineState) NewTaskHandler() NewTaskHandlerCommand1 {
 
 // Id implements NewTaskHandlerCommand1
 func (thc newTaskHandlerCommand) Id(id string) NewTaskHandlerCommand2 {
-	thc.matcher = func(element *bpmn20.TaskElement) bool {
-		return (*element).GetId() == id
+	thc.matcher = func(element bpmn20.TaskElement) bool {
+		return element.GetId() == id
 	}
 	thc.handlerType = taskHandlerForId
 	return thc
@@ -71,8 +71,8 @@ func (thc newTaskHandlerCommand) Id(id string) NewTaskHandlerCommand2 {
 
 // Type implements NewTaskHandlerCommand1
 func (thc newTaskHandlerCommand) Type(taskType string) NewTaskHandlerCommand2 {
-	thc.matcher = func(element *bpmn20.TaskElement) bool {
-		return (*element).GetTaskDefinitionType() == taskType
+	thc.matcher = func(element bpmn20.TaskElement) bool {
+		return element.GetTaskDefinitionType() == taskType
 	}
 	thc.handlerType = taskHandlerForType
 	return thc
@@ -90,8 +90,8 @@ func (thc newTaskHandlerCommand) Handler(f func(job ActivatedJob)) {
 
 // Assignee implements NewTaskHandlerCommand2
 func (thc newTaskHandlerCommand) Assignee(assignee string) NewTaskHandlerCommand2 {
-	thc.matcher = func(element *bpmn20.TaskElement) bool {
-		return (*element).GetAssignmentAssignee() == assignee
+	thc.matcher = func(element bpmn20.TaskElement) bool {
+		return element.GetAssignmentAssignee() == assignee
 	}
 	thc.handlerType = taskHandlerForAssignee
 	return thc
@@ -99,9 +99,9 @@ func (thc newTaskHandlerCommand) Assignee(assignee string) NewTaskHandlerCommand
 
 // CandidateGroups implements NewTaskHandlerCommand2
 func (thc newTaskHandlerCommand) CandidateGroups(groups ...string) NewTaskHandlerCommand2 {
-	thc.matcher = func(element *bpmn20.TaskElement) bool {
+	thc.matcher = func(element bpmn20.TaskElement) bool {
 		for _, group := range groups {
-			if contains((*element).GetAssignmentCandidateGroups(), group) {
+			if contains(element.GetAssignmentCandidateGroups(), group) {
 				return true
 			}
 		}
@@ -111,12 +111,12 @@ func (thc newTaskHandlerCommand) CandidateGroups(groups ...string) NewTaskHandle
 	return thc
 }
 
-func (state *BpmnEngineState) findTaskHandler(element *bpmn20.TaskElement) func(job ActivatedJob) {
+func (state *BpmnEngineState) findTaskHandler(element bpmn20.TaskElement) func(job ActivatedJob) {
 	searchOrder := []taskHandlerType{taskHandlerForId}
-	if (*element).GetType() == bpmn20.ServiceTask {
+	if element.GetType() == bpmn20.ServiceTask {
 		searchOrder = append(searchOrder, taskHandlerForType)
 	}
-	if (*element).GetType() == bpmn20.UserTask {
+	if element.GetType() == bpmn20.UserTask {
 		searchOrder = append(searchOrder, taskHandlerForAssignee, taskHandlerForCandidateGroups)
 	}
 	for _, handlerType := range searchOrder {
diff --git a/pkg/bpmn/timer.go b/pkg/bpmn/timer.go
index 733afa40..c72c5dca 100644
--- a/pkg/bpmn/timer.go
+++ b/pkg/bpmn/timer.go
@@ -22,7 +22,7 @@ type Timer struct {
 	DueAt              time.Time     `json:"da"`
 	Duration           time.Duration `json:"du"`
 	originActivity     activity
-	baseElement        *bpmn20.BaseElement
+	baseElement        bpmn20.FlowNode
 }
 
 type TimerState string
@@ -47,7 +47,7 @@ func (t Timer) State() ActivityState {
 	panic(fmt.Sprintf("[invariant check] missing mapping for timer state=%s", t.TimerState))
 }
 
-func (t Timer) Element() *bpmn20.BaseElement {
+func (t Timer) Element() bpmn20.FlowNode {
 	return t.baseElement
 }
 
@@ -56,8 +56,8 @@ func (state *BpmnEngineState) handleIntermediateTimerCatchEvent(instance *proces
 
 	if timer != nil && timer.originActivity != nil {
 		originActivity := instance.findActivity(timer.originActivity.Key())
-		if originActivity != nil && (*originActivity.Element()).GetType() == bpmn20.EventBasedGateway {
-			ebgActivity := originActivity.(*eventBasedGatewayActivity)
+		if originActivity != nil && originActivity.Element().GetType() == bpmn20.EventBasedGateway {
+			ebgActivity := originActivity.(eventBasedGatewayActivity)
 			if ebgActivity.OutboundCompleted() {
 				timer.TimerState = TimerCancelled
 				return false, timer, err
@@ -69,7 +69,7 @@ func (state *BpmnEngineState) handleIntermediateTimerCatchEvent(instance *proces
 		timer, err = state.createTimer(instance, ice, originActivity)
 		if err != nil {
 			evalErr := &ExpressionEvaluationError{
-				Msg: fmt.Sprintf("Error evaluating expression in intermediate timer cacht event element id='%s' name='%s'", ice.Id, ice.Name),
+				Msg: fmt.Sprintf("Error evaluating expression in intermediate timer cacht event activity id='%s' name='%s'", ice.Id, ice.Name),
 				Err: err,
 			}
 			return false, timer, evalErr
@@ -80,8 +80,8 @@ func (state *BpmnEngineState) handleIntermediateTimerCatchEvent(instance *proces
 		timer.TimerState = TimerTriggered
 		if timer.originActivity != nil {
 			originActivity := instance.findActivity(timer.originActivity.Key())
-			if originActivity != nil && (*originActivity.Element()).GetType() == bpmn20.EventBasedGateway {
-				ebgActivity := originActivity.(*eventBasedGatewayActivity)
+			if originActivity != nil && originActivity.Element().GetType() == bpmn20.EventBasedGateway {
+				ebgActivity := originActivity.(eventBasedGatewayActivity)
 				ebgActivity.SetOutboundCompleted(ice.Id)
 			}
 		}
@@ -94,9 +94,9 @@ func (state *BpmnEngineState) createTimer(instance *processInstanceInfo, ice bpm
 	durationVal, err := findDurationValue(ice)
 	if err != nil {
 		return nil, &BpmnEngineError{Msg: fmt.Sprintf("Error parsing 'timeDuration' value "+
-			"from element with ID=%s. Error:%s", ice.Id, err.Error())}
+			"from activity with ID=%s. Error:%s", ice.Id, err.Error())}
 	}
-	var be bpmn20.BaseElement = ice
+	var be bpmn20.FlowNode = ice
 	now := time.Now()
 	t := &Timer{
 		ElementId:          ice.Id,
@@ -107,11 +107,11 @@ func (state *BpmnEngineState) createTimer(instance *processInstanceInfo, ice bpm
 		CreatedAt:          now,
 		DueAt:              durationVal.Shift(now),
 		Duration:           time.Duration(durationVal.TS) * time.Second,
-		baseElement:        &be,
+		baseElement:        be,
 		originActivity:     originActivity,
 	}
-	state.persistence.PersistNewTimer(t)
-	return t, nil
+	_err := state.persistence.PersistNewTimer(t)
+	return t, _err
 }
 
 func findExistingTimerNotYetTriggered(state *BpmnEngineState, id string, instance *processInstanceInfo) *Timer {
diff --git a/pkg/bpmn/usertasks.go b/pkg/bpmn/usertasks.go
index cc694a5e..c709bf10 100644
--- a/pkg/bpmn/usertasks.go
+++ b/pkg/bpmn/usertasks.go
@@ -2,7 +2,7 @@ package bpmn
 
 import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/bpmn20"
 
-func (state *BpmnEngineState) handleUserTask(process *ProcessInfo, instance *processInstanceInfo, element *bpmn20.TaskElement) *job {
+func (state *BpmnEngineState) handleUserTask(process *ProcessInfo, instance *processInstanceInfo, element bpmn20.TaskElement) *job {
 	// TODO consider different handlers, since Service Tasks are different in their definition than user tasks
 	_, j := state.handleServiceTask(process, instance, element)
 	return j


Reviews:
user: login: nitram509
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-05T13:25:52Z
user: login: dmytro-gundartsev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T13:29:21Z
user: login: richardbizik
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T13:34:14Z
user: login: dmytro-gundartsev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T13:48:25Z

Review comments:
diff_hunk: @@ -69,23 +69,23 @@ func (startEvent TStartEvent) GetType() ElementType {
 	return StartEvent
 }
 
-func (endEvent TEndEvent) GetId() string {
-	return endEvent.Id
+func (act TEndEvent) GetId() string {
path: pkg/bpmn/model/bpmn20/elements.go
user: login: nitram509
body: the receiver name should be `endEvent` (instead of `act`), to be consistent in naming, no?

created_at: 2025-03-05T13:04:57Z
author_association: MEMBER
diff_hunk: @@ -25,16 +25,16 @@ const (
 	Mixed       GatewayDirection = "Mixed"
 )
 
-type BaseElement interface {
-	GetId() string
-	GetName() string
-	GetIncomingAssociation() []string
-	GetOutgoingAssociation() []string
-	GetType() ElementType
-}
+//type BaseElement interface {
path: pkg/bpmn/model/bpmn20/elements.go
user: login: nitram509
body: this commented out type def can be removed.
created_at: 2025-03-05T13:05:18Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,129 @@
+package bpmn20
+
+// All BPMN elements that inherit from the BaseElement will have the capability,
+// through the Documentation element, to have one (1) or more text descriptions
+// of that element.
+type TDocumentation struct {
path: pkg/bpmn/model/bpmn20/core.go
user: login: nitram509
body: I like the idea of adding Documentation and FlowNode elements, good job 👍 
created_at: 2025-03-05T13:05:53Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,129 @@
+package bpmn20
+
+// All BPMN elements that inherit from the BaseElement will have the capability,
path: pkg/bpmn/model/bpmn20/core.go
user: login: nitram509
body: Minor thing: Go conventions say the first word in the doc string must literally match the type identifier.
```suggestion
// TDocumentation all BPMN elements that inherit from the BaseElement will have the capability,
```
created_at: 2025-03-05T13:08:50Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,149 @@
+package bpmn20
+
+import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
+
+type TFlowElementsContainer struct {
+	StartEvents            []TStartEvent             `xml:"startEvent"`
+	EndEvents              []TEndEvent               `xml:"endEvent"`
+	SequenceFlows          []TSequenceFlow           `xml:"sequenceFlow"`
+	ServiceTasks           []TServiceTask            `xml:"serviceTask"`
+	UserTasks              []TUserTask               `xml:"userTask"`
+	ParallelGateway        []TParallelGateway        `xml:"parallelGateway"`
+	ExclusiveGateway       []TExclusiveGateway       `xml:"exclusiveGateway"`
+	IntermediateCatchEvent []TIntermediateCatchEvent `xml:"intermediateCatchEvent"`
+	IntermediateThrowEvent []TIntermediateThrowEvent `xml:"intermediateThrowEvent"`
+	EventBasedGateway      []TEventBasedGateway      `xml:"eventBasedGateway"`
+	InclusiveGateway       []TInclusiveGateway       `xml:"inclusiveGateway"`
+}
+
+type TProcess struct {
+	TCallableElement
+	TFlowElementsContainer
+	ProcessType                  string `xml:"processType,attr"`
+	IsClosed                     bool   `xml:"isClosed,attr"`
+	IsExecutable                 bool   `xml:"isExecutable,attr"`
+	DefinitionalCollaborationRef string `xml:"definitionalCollaborationRef,attr"`
+}
+
+type Activity interface {
+	FlowNode
+	GetCompletionQuantity() int
+	GetIsForCompensation() bool
+	GetStartQuantity() int
+}
+
+type TActivity struct {
+	TFlowNode
+	CompletionQuantity int  `xml:"completionQuantity,attr"`
+	IsForCompensation  bool `xml:"isForCompensation,attr"`
+	StartQuantity      int  `xml:"startQuantity,attr"`
+}
+type TTask struct {
+	TActivity
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Input  []extensions.TIoMapping `xml:"extensionElements>ioMapping>input"`
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TGateway struct {
+	TFlowNode
+	GatewayDirection GatewayDirection `xml:"gatewayDirection,attr"`
+}
+
+type TEvent = TActivity
+
+// ExternallyProcessedTask is to be processed by external Job workers. Is not part of original BPMN Implementation
+// BPMN 2.0 Unorthodox.
+type TExternallyProcessedTask struct {
+	TTask
+	TaskDefinition extensions.TTaskDefinition `xml:"extensionElements>taskDefinition"`
+}
+type TServiceTask struct {
+	TExternallyProcessedTask
+	OperationRef   string `xml:"operationRef,attr"`
+	Implementation string `xml:"implementation,attr"`
+}
+
+// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+type TUserTask struct {
+	TTask
+	AssignmentDefinition extensions.TAssignmentDefinition `xml:"extensionElements>assignmentDefinition"`
+}
+
+type TInclusiveGateway struct {
+	TGateway
+}
+
+type TParallelGateway struct {
+	TGateway
+}
+
+type TExclusiveGateway struct {
+	TGateway
+}
+
+type TEventBasedGateway struct {
+	TGateway
+	Instantiate      bool                  `xml:"instantiate,attr"`
+	EventGatewayType EventBasedGatewayType `xml:"eventGatewayType,attr"`
+}
+type EventBasedGatewayType = string
+
+const (
+	EventBasedGatewayTypeExclusive EventBasedGatewayType = "Exclusive"
+	EventBasedGatewayTypeParallel  EventBasedGatewayType = "Parallel"
+)
+
+type TStartEvent struct {
+	TEvent
+	IsInterrupting   bool `xml:"isInterrupting,attr"`
+	ParallelMultiple bool `xml:"parallelMultiple,attr"`
+}
+
+type TEndEvent = TEvent
+
+type TIntermediateCatchEvent struct {
+	TEvent
+	MessageEventDefinition TMessageEventDefinition `xml:"messageEventDefinition"`
+	TimerEventDefinition   TTimerEventDefinition   `xml:"timerEventDefinition"`
+	LinkEventDefinition    TLinkEventDefinition    `xml:"linkEventDefinition"`
+	ParallelMultiple       bool                    `xml:"parallelMultiple"`
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TIntermediateThrowEvent struct {
+	TEvent
+	LinkEventDefinition TLinkEventDefinition `xml:"linkEventDefinition"`
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TMessageEventDefinition struct {
+	Id         string `xml:"id,attr"`
+	MessageRef string `xml:"messageRef,attr"`
+}
+
+type TTimerEventDefinition struct {
+	Id           string        `xml:"id,attr"`
+	TimeDuration TTimeDuration `xml:"timeDuration"`
+}
+
+type TLinkEventDefinition struct {
+	Id   string `xml:"id,attr"`
+	Name string `xml:"name,attr"`
+}
+
+type TTimeDuration struct {
+	XMLText string `xml:",innerxml"`
+}
+
+func (act TActivity) GetCompletionQuantity() int {
path: pkg/bpmn/model/bpmn20/process.go
user: login: nitram509
body: since the names of the interfaces are very similar, I do recommend to not use abbreviations,
but instead using full name for the receiver variable ... `activity` instead of `act`
created_at: 2025-03-05T13:10:42Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,129 @@
+package bpmn20
+
+// All BPMN elements that inherit from the BaseElement will have the capability,
+// through the Documentation element, to have one (1) or more text descriptions
+// of that element.
+type TDocumentation struct {
+	// This attribute is used to capture the text descriptions of a
+	// BPMN element.
+	Text string `xml:"text,text"`
+
+	// This attribute identifies the format of the text. It MUST follow
+	// the mime-type format. The default is "text/plain".
+	Format string `xml:"textFormat,attr"`
+}
+
+func (doc TDocumentation) GetText() string {
+	return doc.Text
+}
+
+func (doc TDocumentation) GetFormat() string {
+	return doc.Format
+}
+
+type TBaseElement struct {
+	// This attribute is used to uniquely identify BPMN elements. The id is
+	// REQUIRED if this element is referenced or intended to be referenced by
+	// something else. If the element is not currently referenced and is never
+	// intended to be referenced, the id MAY be omitted.
+	Id string `xml:"id,attr"`
+
+	// This attribute is used to annotate the BPMN element, such as descriptions
+	// and other documentation.
+	Documentation []TDocumentation `xml:"documentation"`
+}
+
+func (t TBaseElement) GetId() string {
+	return t.Id
+}
+func (t TBaseElement) GetDocumentation() []Documentation {
+	var docs []Documentation
path: pkg/bpmn/model/bpmn20/core.go
user: login: nitram509
body: it seems to me a copy is made here.
what's the reason?
would it be feasible to just return t.Documentation?
created_at: 2025-03-05T13:16:29Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,149 @@
+package bpmn20
+
+import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
+
+type TFlowElementsContainer struct {
+	StartEvents            []TStartEvent             `xml:"startEvent"`
+	EndEvents              []TEndEvent               `xml:"endEvent"`
+	SequenceFlows          []TSequenceFlow           `xml:"sequenceFlow"`
+	ServiceTasks           []TServiceTask            `xml:"serviceTask"`
+	UserTasks              []TUserTask               `xml:"userTask"`
+	ParallelGateway        []TParallelGateway        `xml:"parallelGateway"`
+	ExclusiveGateway       []TExclusiveGateway       `xml:"exclusiveGateway"`
+	IntermediateCatchEvent []TIntermediateCatchEvent `xml:"intermediateCatchEvent"`
+	IntermediateThrowEvent []TIntermediateThrowEvent `xml:"intermediateThrowEvent"`
+	EventBasedGateway      []TEventBasedGateway      `xml:"eventBasedGateway"`
+	InclusiveGateway       []TInclusiveGateway       `xml:"inclusiveGateway"`
+}
+
+type TProcess struct {
+	TCallableElement
+	TFlowElementsContainer
+	ProcessType                  string `xml:"processType,attr"`
+	IsClosed                     bool   `xml:"isClosed,attr"`
+	IsExecutable                 bool   `xml:"isExecutable,attr"`
+	DefinitionalCollaborationRef string `xml:"definitionalCollaborationRef,attr"`
+}
+
+type Activity interface {
+	FlowNode
+	GetCompletionQuantity() int
+	GetIsForCompensation() bool
+	GetStartQuantity() int
+}
+
+type TActivity struct {
+	TFlowNode
+	CompletionQuantity int  `xml:"completionQuantity,attr"`
+	IsForCompensation  bool `xml:"isForCompensation,attr"`
+	StartQuantity      int  `xml:"startQuantity,attr"`
+}
+type TTask struct {
+	TActivity
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Input  []extensions.TIoMapping `xml:"extensionElements>ioMapping>input"`
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TGateway struct {
+	TFlowNode
+	GatewayDirection GatewayDirection `xml:"gatewayDirection,attr"`
+}
+
+type TEvent = TActivity
+
+// ExternallyProcessedTask is to be processed by external Job workers. Is not part of original BPMN Implementation
+// BPMN 2.0 Unorthodox.
+type TExternallyProcessedTask struct {
+	TTask
+	TaskDefinition extensions.TTaskDefinition `xml:"extensionElements>taskDefinition"`
+}
+type TServiceTask struct {
+	TExternallyProcessedTask
+	OperationRef   string `xml:"operationRef,attr"`
+	Implementation string `xml:"implementation,attr"`
+}
+
+// BPMN 2.0 Unorthodox elements. Part of the extensions elements
path: pkg/bpmn/model/bpmn20/process.go
user: login: nitram509
body: I have read the 538 pages of BPMN 2.0 2011-01-03, and found UserTask is documented.
It's part of the standard and so this comment should be dropped, no?
created_at: 2025-03-05T13:20:29Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,149 @@
+package bpmn20
+
+import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
+
+type TFlowElementsContainer struct {
+	StartEvents            []TStartEvent             `xml:"startEvent"`
+	EndEvents              []TEndEvent               `xml:"endEvent"`
+	SequenceFlows          []TSequenceFlow           `xml:"sequenceFlow"`
+	ServiceTasks           []TServiceTask            `xml:"serviceTask"`
+	UserTasks              []TUserTask               `xml:"userTask"`
+	ParallelGateway        []TParallelGateway        `xml:"parallelGateway"`
+	ExclusiveGateway       []TExclusiveGateway       `xml:"exclusiveGateway"`
+	IntermediateCatchEvent []TIntermediateCatchEvent `xml:"intermediateCatchEvent"`
+	IntermediateThrowEvent []TIntermediateThrowEvent `xml:"intermediateThrowEvent"`
+	EventBasedGateway      []TEventBasedGateway      `xml:"eventBasedGateway"`
+	InclusiveGateway       []TInclusiveGateway       `xml:"inclusiveGateway"`
+}
+
+type TProcess struct {
+	TCallableElement
+	TFlowElementsContainer
+	ProcessType                  string `xml:"processType,attr"`
+	IsClosed                     bool   `xml:"isClosed,attr"`
+	IsExecutable                 bool   `xml:"isExecutable,attr"`
+	DefinitionalCollaborationRef string `xml:"definitionalCollaborationRef,attr"`
+}
+
+type Activity interface {
+	FlowNode
+	GetCompletionQuantity() int
+	GetIsForCompensation() bool
+	GetStartQuantity() int
+}
+
+type TActivity struct {
+	TFlowNode
+	CompletionQuantity int  `xml:"completionQuantity,attr"`
+	IsForCompensation  bool `xml:"isForCompensation,attr"`
+	StartQuantity      int  `xml:"startQuantity,attr"`
+}
+type TTask struct {
+	TActivity
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Input  []extensions.TIoMapping `xml:"extensionElements>ioMapping>input"`
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TGateway struct {
+	TFlowNode
+	GatewayDirection GatewayDirection `xml:"gatewayDirection,attr"`
+}
+
+type TEvent = TActivity
+
+// ExternallyProcessedTask is to be processed by external Job workers. Is not part of original BPMN Implementation
path: pkg/bpmn/model/bpmn20/process.go
user: login: nitram509
body: ```suggestion
// TExternallyProcessedTask is to be processed by external Job workers. Is not part of original BPMN Implementation
```

See comment above about Go conventions.
created_at: 2025-03-05T13:21:27Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,149 @@
+package bpmn20
+
+import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
+
+type TFlowElementsContainer struct {
+	StartEvents            []TStartEvent             `xml:"startEvent"`
+	EndEvents              []TEndEvent               `xml:"endEvent"`
+	SequenceFlows          []TSequenceFlow           `xml:"sequenceFlow"`
+	ServiceTasks           []TServiceTask            `xml:"serviceTask"`
+	UserTasks              []TUserTask               `xml:"userTask"`
+	ParallelGateway        []TParallelGateway        `xml:"parallelGateway"`
+	ExclusiveGateway       []TExclusiveGateway       `xml:"exclusiveGateway"`
+	IntermediateCatchEvent []TIntermediateCatchEvent `xml:"intermediateCatchEvent"`
+	IntermediateThrowEvent []TIntermediateThrowEvent `xml:"intermediateThrowEvent"`
+	EventBasedGateway      []TEventBasedGateway      `xml:"eventBasedGateway"`
+	InclusiveGateway       []TInclusiveGateway       `xml:"inclusiveGateway"`
+}
+
+type TProcess struct {
+	TCallableElement
+	TFlowElementsContainer
+	ProcessType                  string `xml:"processType,attr"`
+	IsClosed                     bool   `xml:"isClosed,attr"`
+	IsExecutable                 bool   `xml:"isExecutable,attr"`
+	DefinitionalCollaborationRef string `xml:"definitionalCollaborationRef,attr"`
+}
+
+type Activity interface {
+	FlowNode
+	GetCompletionQuantity() int
+	GetIsForCompensation() bool
+	GetStartQuantity() int
+}
+
+type TActivity struct {
+	TFlowNode
+	CompletionQuantity int  `xml:"completionQuantity,attr"`
+	IsForCompensation  bool `xml:"isForCompensation,attr"`
+	StartQuantity      int  `xml:"startQuantity,attr"`
+}
+type TTask struct {
+	TActivity
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Input  []extensions.TIoMapping `xml:"extensionElements>ioMapping>input"`
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TGateway struct {
+	TFlowNode
+	GatewayDirection GatewayDirection `xml:"gatewayDirection,attr"`
+}
+
+type TEvent = TActivity
+
+// ExternallyProcessedTask is to be processed by external Job workers. Is not part of original BPMN Implementation
+// BPMN 2.0 Unorthodox.
+type TExternallyProcessedTask struct {
+	TTask
+	TaskDefinition extensions.TTaskDefinition `xml:"extensionElements>taskDefinition"`
+}
+type TServiceTask struct {
+	TExternallyProcessedTask
+	OperationRef   string `xml:"operationRef,attr"`
+	Implementation string `xml:"implementation,attr"`
+}
+
+// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+type TUserTask struct {
+	TTask
+	AssignmentDefinition extensions.TAssignmentDefinition `xml:"extensionElements>assignmentDefinition"`
+}
+
+type TInclusiveGateway struct {
+	TGateway
+}
+
+type TParallelGateway struct {
+	TGateway
+}
+
+type TExclusiveGateway struct {
+	TGateway
+}
+
+type TEventBasedGateway struct {
+	TGateway
+	Instantiate      bool                  `xml:"instantiate,attr"`
+	EventGatewayType EventBasedGatewayType `xml:"eventGatewayType,attr"`
+}
+type EventBasedGatewayType = string
+
+const (
+	EventBasedGatewayTypeExclusive EventBasedGatewayType = "Exclusive"
path: pkg/bpmn/model/bpmn20/process.go
user: login: nitram509
body: these two constants are not yet used ... is this by intent?
created_at: 2025-03-05T13:22:57Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,149 @@
+package bpmn20
+
+import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
+
+type TFlowElementsContainer struct {
+	StartEvents            []TStartEvent             `xml:"startEvent"`
+	EndEvents              []TEndEvent               `xml:"endEvent"`
+	SequenceFlows          []TSequenceFlow           `xml:"sequenceFlow"`
+	ServiceTasks           []TServiceTask            `xml:"serviceTask"`
+	UserTasks              []TUserTask               `xml:"userTask"`
+	ParallelGateway        []TParallelGateway        `xml:"parallelGateway"`
+	ExclusiveGateway       []TExclusiveGateway       `xml:"exclusiveGateway"`
+	IntermediateCatchEvent []TIntermediateCatchEvent `xml:"intermediateCatchEvent"`
+	IntermediateThrowEvent []TIntermediateThrowEvent `xml:"intermediateThrowEvent"`
+	EventBasedGateway      []TEventBasedGateway      `xml:"eventBasedGateway"`
+	InclusiveGateway       []TInclusiveGateway       `xml:"inclusiveGateway"`
+}
+
+type TProcess struct {
+	TCallableElement
+	TFlowElementsContainer
+	ProcessType                  string `xml:"processType,attr"`
+	IsClosed                     bool   `xml:"isClosed,attr"`
+	IsExecutable                 bool   `xml:"isExecutable,attr"`
+	DefinitionalCollaborationRef string `xml:"definitionalCollaborationRef,attr"`
+}
+
+type Activity interface {
+	FlowNode
+	GetCompletionQuantity() int
+	GetIsForCompensation() bool
+	GetStartQuantity() int
+}
+
+type TActivity struct {
+	TFlowNode
+	CompletionQuantity int  `xml:"completionQuantity,attr"`
+	IsForCompensation  bool `xml:"isForCompensation,attr"`
+	StartQuantity      int  `xml:"startQuantity,attr"`
+}
+type TTask struct {
+	TActivity
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Input  []extensions.TIoMapping `xml:"extensionElements>ioMapping>input"`
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TGateway struct {
+	TFlowNode
+	GatewayDirection GatewayDirection `xml:"gatewayDirection,attr"`
+}
+
+type TEvent = TActivity
+
+// ExternallyProcessedTask is to be processed by external Job workers. Is not part of original BPMN Implementation
+// BPMN 2.0 Unorthodox.
+type TExternallyProcessedTask struct {
+	TTask
+	TaskDefinition extensions.TTaskDefinition `xml:"extensionElements>taskDefinition"`
+}
+type TServiceTask struct {
+	TExternallyProcessedTask
+	OperationRef   string `xml:"operationRef,attr"`
+	Implementation string `xml:"implementation,attr"`
+}
+
+// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+type TUserTask struct {
+	TTask
+	AssignmentDefinition extensions.TAssignmentDefinition `xml:"extensionElements>assignmentDefinition"`
+}
+
+type TInclusiveGateway struct {
+	TGateway
+}
+
+type TParallelGateway struct {
+	TGateway
+}
+
+type TExclusiveGateway struct {
+	TGateway
+}
+
+type TEventBasedGateway struct {
+	TGateway
+	Instantiate      bool                  `xml:"instantiate,attr"`
+	EventGatewayType EventBasedGatewayType `xml:"eventGatewayType,attr"`
+}
+type EventBasedGatewayType = string
+
+const (
+	EventBasedGatewayTypeExclusive EventBasedGatewayType = "Exclusive"
+	EventBasedGatewayTypeParallel  EventBasedGatewayType = "Parallel"
+)
+
+type TStartEvent struct {
+	TEvent
+	IsInterrupting   bool `xml:"isInterrupting,attr"`
+	ParallelMultiple bool `xml:"parallelMultiple,attr"`
+}
+
+type TEndEvent = TEvent
+
+type TIntermediateCatchEvent struct {
+	TEvent
+	MessageEventDefinition TMessageEventDefinition `xml:"messageEventDefinition"`
+	TimerEventDefinition   TTimerEventDefinition   `xml:"timerEventDefinition"`
+	LinkEventDefinition    TLinkEventDefinition    `xml:"linkEventDefinition"`
+	ParallelMultiple       bool                    `xml:"parallelMultiple"`
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
path: pkg/bpmn/model/bpmn20/process.go
user: login: nitram509
body: I like the explicit flagging of extensions 👍 
created_at: 2025-03-05T13:23:31Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,129 @@
+package bpmn20
+
+// All BPMN elements that inherit from the BaseElement will have the capability,
+// through the Documentation element, to have one (1) or more text descriptions
+// of that element.
+type TDocumentation struct {
+	// This attribute is used to capture the text descriptions of a
+	// BPMN element.
+	Text string `xml:"text,text"`
+
+	// This attribute identifies the format of the text. It MUST follow
+	// the mime-type format. The default is "text/plain".
+	Format string `xml:"textFormat,attr"`
+}
+
+func (doc TDocumentation) GetText() string {
+	return doc.Text
+}
+
+func (doc TDocumentation) GetFormat() string {
+	return doc.Format
+}
+
+type TBaseElement struct {
+	// This attribute is used to uniquely identify BPMN elements. The id is
+	// REQUIRED if this element is referenced or intended to be referenced by
+	// something else. If the element is not currently referenced and is never
+	// intended to be referenced, the id MAY be omitted.
+	Id string `xml:"id,attr"`
+
+	// This attribute is used to annotate the BPMN element, such as descriptions
+	// and other documentation.
+	Documentation []TDocumentation `xml:"documentation"`
+}
+
+func (t TBaseElement) GetId() string {
+	return t.Id
+}
+func (t TBaseElement) GetDocumentation() []Documentation {
+	var docs []Documentation
+	for _, doc := range t.Documentation {
+		docs = append(docs, doc)
+	}
+	return docs
+}
+
+type Documentation interface {
+	GetText() string
+	GetFormat() string
+}
+
+type BaseElement interface {
path: pkg/bpmn/model/bpmn20/core.go
user: login: nitram509
body: ```suggestion
// BaseElement is the abstract super class/interface for most BPMN elements.
// It provides the attributes id and documentation, which other elements will inherit.
type BaseElement interface {
```

just some more docstring, copied from the spec.
created_at: 2025-03-05T13:25:40Z
author_association: MEMBER
diff_hunk: @@ -69,23 +69,23 @@ func (startEvent TStartEvent) GetType() ElementType {
 	return StartEvent
 }
 
-func (endEvent TEndEvent) GetId() string {
-	return endEvent.Id
+func (act TEndEvent) GetId() string {
path: pkg/bpmn/model/bpmn20/elements.go
user: login: dmytro-gundartsev
body: Thank you. Changing ...
created_at: 2025-03-05T13:29:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,129 @@
+package bpmn20
+
+// All BPMN elements that inherit from the BaseElement will have the capability,
+// through the Documentation element, to have one (1) or more text descriptions
+// of that element.
+type TDocumentation struct {
+	// This attribute is used to capture the text descriptions of a
+	// BPMN element.
+	Text string `xml:"text,text"`
+
+	// This attribute identifies the format of the text. It MUST follow
+	// the mime-type format. The default is "text/plain".
+	Format string `xml:"textFormat,attr"`
+}
+
+func (doc TDocumentation) GetText() string {
+	return doc.Text
+}
+
+func (doc TDocumentation) GetFormat() string {
+	return doc.Format
+}
+
+type TBaseElement struct {
+	// This attribute is used to uniquely identify BPMN elements. The id is
+	// REQUIRED if this element is referenced or intended to be referenced by
+	// something else. If the element is not currently referenced and is never
+	// intended to be referenced, the id MAY be omitted.
+	Id string `xml:"id,attr"`
+
+	// This attribute is used to annotate the BPMN element, such as descriptions
+	// and other documentation.
+	Documentation []TDocumentation `xml:"documentation"`
+}
+
+func (t TBaseElement) GetId() string {
+	return t.Id
+}
+func (t TBaseElement) GetDocumentation() []Documentation {
+	var docs []Documentation
path: pkg/bpmn/model/bpmn20/core.go
user: login: richardbizik
body: I guess its because Documentation is an interface and you cannot cast array of structs to interface. Could we use the `Documentation` interface in TBaseEleent?
created_at: 2025-03-05T13:29:49Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,149 @@
+package bpmn20
+
+import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
+
+type TFlowElementsContainer struct {
+	StartEvents            []TStartEvent             `xml:"startEvent"`
+	EndEvents              []TEndEvent               `xml:"endEvent"`
+	SequenceFlows          []TSequenceFlow           `xml:"sequenceFlow"`
+	ServiceTasks           []TServiceTask            `xml:"serviceTask"`
+	UserTasks              []TUserTask               `xml:"userTask"`
+	ParallelGateway        []TParallelGateway        `xml:"parallelGateway"`
+	ExclusiveGateway       []TExclusiveGateway       `xml:"exclusiveGateway"`
+	IntermediateCatchEvent []TIntermediateCatchEvent `xml:"intermediateCatchEvent"`
+	IntermediateThrowEvent []TIntermediateThrowEvent `xml:"intermediateThrowEvent"`
+	EventBasedGateway      []TEventBasedGateway      `xml:"eventBasedGateway"`
+	InclusiveGateway       []TInclusiveGateway       `xml:"inclusiveGateway"`
+}
+
+type TProcess struct {
+	TCallableElement
+	TFlowElementsContainer
+	ProcessType                  string `xml:"processType,attr"`
+	IsClosed                     bool   `xml:"isClosed,attr"`
+	IsExecutable                 bool   `xml:"isExecutable,attr"`
+	DefinitionalCollaborationRef string `xml:"definitionalCollaborationRef,attr"`
+}
+
+type Activity interface {
+	FlowNode
+	GetCompletionQuantity() int
+	GetIsForCompensation() bool
+	GetStartQuantity() int
+}
+
+type TActivity struct {
+	TFlowNode
+	CompletionQuantity int  `xml:"completionQuantity,attr"`
+	IsForCompensation  bool `xml:"isForCompensation,attr"`
+	StartQuantity      int  `xml:"startQuantity,attr"`
+}
+type TTask struct {
+	TActivity
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Input  []extensions.TIoMapping `xml:"extensionElements>ioMapping>input"`
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TGateway struct {
+	TFlowNode
+	GatewayDirection GatewayDirection `xml:"gatewayDirection,attr"`
+}
+
+type TEvent = TActivity
+
+// ExternallyProcessedTask is to be processed by external Job workers. Is not part of original BPMN Implementation
+// BPMN 2.0 Unorthodox.
+type TExternallyProcessedTask struct {
+	TTask
+	TaskDefinition extensions.TTaskDefinition `xml:"extensionElements>taskDefinition"`
+}
+type TServiceTask struct {
+	TExternallyProcessedTask
+	OperationRef   string `xml:"operationRef,attr"`
+	Implementation string `xml:"implementation,attr"`
+}
+
+// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+type TUserTask struct {
+	TTask
+	AssignmentDefinition extensions.TAssignmentDefinition `xml:"extensionElements>assignmentDefinition"`
+}
+
+type TInclusiveGateway struct {
+	TGateway
+}
+
+type TParallelGateway struct {
+	TGateway
+}
+
+type TExclusiveGateway struct {
+	TGateway
+}
+
+type TEventBasedGateway struct {
+	TGateway
+	Instantiate      bool                  `xml:"instantiate,attr"`
+	EventGatewayType EventBasedGatewayType `xml:"eventGatewayType,attr"`
+}
+type EventBasedGatewayType = string
+
+const (
+	EventBasedGatewayTypeExclusive EventBasedGatewayType = "Exclusive"
+	EventBasedGatewayTypeParallel  EventBasedGatewayType = "Parallel"
+)
+
+type TStartEvent struct {
+	TEvent
+	IsInterrupting   bool `xml:"isInterrupting,attr"`
+	ParallelMultiple bool `xml:"parallelMultiple,attr"`
+}
+
+type TEndEvent = TEvent
+
+type TIntermediateCatchEvent struct {
+	TEvent
+	MessageEventDefinition TMessageEventDefinition `xml:"messageEventDefinition"`
+	TimerEventDefinition   TTimerEventDefinition   `xml:"timerEventDefinition"`
+	LinkEventDefinition    TLinkEventDefinition    `xml:"linkEventDefinition"`
+	ParallelMultiple       bool                    `xml:"parallelMultiple"`
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TIntermediateThrowEvent struct {
+	TEvent
+	LinkEventDefinition TLinkEventDefinition `xml:"linkEventDefinition"`
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TMessageEventDefinition struct {
+	Id         string `xml:"id,attr"`
+	MessageRef string `xml:"messageRef,attr"`
+}
+
+type TTimerEventDefinition struct {
+	Id           string        `xml:"id,attr"`
+	TimeDuration TTimeDuration `xml:"timeDuration"`
+}
+
+type TLinkEventDefinition struct {
+	Id   string `xml:"id,attr"`
+	Name string `xml:"name,attr"`
+}
+
+type TTimeDuration struct {
+	XMLText string `xml:",innerxml"`
+}
+
+func (act TActivity) GetCompletionQuantity() int {
path: pkg/bpmn/model/bpmn20/process.go
user: login: richardbizik
body: I would argue that its ok and even idiomatic to have short receiver names (usually only one letter)
created_at: 2025-03-05T13:33:50Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,149 @@
+package bpmn20
+
+import "github.com/pbinitiative/zenbpm/pkg/bpmn/model/extensions"
+
+type TFlowElementsContainer struct {
+	StartEvents            []TStartEvent             `xml:"startEvent"`
+	EndEvents              []TEndEvent               `xml:"endEvent"`
+	SequenceFlows          []TSequenceFlow           `xml:"sequenceFlow"`
+	ServiceTasks           []TServiceTask            `xml:"serviceTask"`
+	UserTasks              []TUserTask               `xml:"userTask"`
+	ParallelGateway        []TParallelGateway        `xml:"parallelGateway"`
+	ExclusiveGateway       []TExclusiveGateway       `xml:"exclusiveGateway"`
+	IntermediateCatchEvent []TIntermediateCatchEvent `xml:"intermediateCatchEvent"`
+	IntermediateThrowEvent []TIntermediateThrowEvent `xml:"intermediateThrowEvent"`
+	EventBasedGateway      []TEventBasedGateway      `xml:"eventBasedGateway"`
+	InclusiveGateway       []TInclusiveGateway       `xml:"inclusiveGateway"`
+}
+
+type TProcess struct {
+	TCallableElement
+	TFlowElementsContainer
+	ProcessType                  string `xml:"processType,attr"`
+	IsClosed                     bool   `xml:"isClosed,attr"`
+	IsExecutable                 bool   `xml:"isExecutable,attr"`
+	DefinitionalCollaborationRef string `xml:"definitionalCollaborationRef,attr"`
+}
+
+type Activity interface {
+	FlowNode
+	GetCompletionQuantity() int
+	GetIsForCompensation() bool
+	GetStartQuantity() int
+}
+
+type TActivity struct {
+	TFlowNode
+	CompletionQuantity int  `xml:"completionQuantity,attr"`
+	IsForCompensation  bool `xml:"isForCompensation,attr"`
+	StartQuantity      int  `xml:"startQuantity,attr"`
+}
+type TTask struct {
+	TActivity
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Input  []extensions.TIoMapping `xml:"extensionElements>ioMapping>input"`
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TGateway struct {
+	TFlowNode
+	GatewayDirection GatewayDirection `xml:"gatewayDirection,attr"`
+}
+
+type TEvent = TActivity
+
+// ExternallyProcessedTask is to be processed by external Job workers. Is not part of original BPMN Implementation
+// BPMN 2.0 Unorthodox.
+type TExternallyProcessedTask struct {
+	TTask
+	TaskDefinition extensions.TTaskDefinition `xml:"extensionElements>taskDefinition"`
+}
+type TServiceTask struct {
+	TExternallyProcessedTask
+	OperationRef   string `xml:"operationRef,attr"`
+	Implementation string `xml:"implementation,attr"`
+}
+
+// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+type TUserTask struct {
+	TTask
+	AssignmentDefinition extensions.TAssignmentDefinition `xml:"extensionElements>assignmentDefinition"`
+}
+
+type TInclusiveGateway struct {
+	TGateway
+}
+
+type TParallelGateway struct {
+	TGateway
+}
+
+type TExclusiveGateway struct {
+	TGateway
+}
+
+type TEventBasedGateway struct {
+	TGateway
+	Instantiate      bool                  `xml:"instantiate,attr"`
+	EventGatewayType EventBasedGatewayType `xml:"eventGatewayType,attr"`
+}
+type EventBasedGatewayType = string
+
+const (
+	EventBasedGatewayTypeExclusive EventBasedGatewayType = "Exclusive"
+	EventBasedGatewayTypeParallel  EventBasedGatewayType = "Parallel"
+)
+
+type TStartEvent struct {
+	TEvent
+	IsInterrupting   bool `xml:"isInterrupting,attr"`
+	ParallelMultiple bool `xml:"parallelMultiple,attr"`
+}
+
+type TEndEvent = TEvent
+
+type TIntermediateCatchEvent struct {
+	TEvent
+	MessageEventDefinition TMessageEventDefinition `xml:"messageEventDefinition"`
+	TimerEventDefinition   TTimerEventDefinition   `xml:"timerEventDefinition"`
+	LinkEventDefinition    TLinkEventDefinition    `xml:"linkEventDefinition"`
+	ParallelMultiple       bool                    `xml:"parallelMultiple"`
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TIntermediateThrowEvent struct {
+	TEvent
+	LinkEventDefinition TLinkEventDefinition `xml:"linkEventDefinition"`
+	// BPMN 2.0 Unorthodox elements. Part of the extensions elements
+	Output []extensions.TIoMapping `xml:"extensionElements>ioMapping>output"`
+}
+
+type TMessageEventDefinition struct {
+	Id         string `xml:"id,attr"`
+	MessageRef string `xml:"messageRef,attr"`
+}
+
+type TTimerEventDefinition struct {
+	Id           string        `xml:"id,attr"`
+	TimeDuration TTimeDuration `xml:"timeDuration"`
+}
+
+type TLinkEventDefinition struct {
+	Id   string `xml:"id,attr"`
+	Name string `xml:"name,attr"`
+}
+
+type TTimeDuration struct {
+	XMLText string `xml:",innerxml"`
+}
+
+func (act TActivity) GetCompletionQuantity() int {
path: pkg/bpmn/model/bpmn20/process.go
user: login: dmytro-gundartsev
body: I would rather keep it unified, for basic BPMN structures I would rather go more verbous. Have changed receiver names. 
created_at: 2025-03-05T13:48:25Z
author_association: CONTRIBUTOR

PR comments:
user: login: richardbizik
created_at: 2025-03-05T12:41:44Z
body: Great job! The only thing I would change is not to use a pointer to interface ( for example `Element() *bpmn20.FlowNode` ). Interface is already a pointer.
author_association: MEMBER
user: login: dmytro-gundartsev
created_at: 2025-03-05T13:24:45Z
body: > Great job! The only thing I would change is not to use a pointer to interface ( for example `Element() *bpmn20.FlowNode` ). Interface is already a pointer.

Roger that. Pushed new commit removing pointers on the interfaces
author_association: CONTRIBUTOR
user: login: dmytro-gundartsev
created_at: 2025-03-05T13:35:09Z
body: > Great job! The only thing I would change is not to use a pointer to interface ( for example `Element() *bpmn20.FlowNode` ). Interface is already a pointer.

Thank you. Done
author_association: CONTRIBUTOR