flow

package module
v0.8.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 27, 2019 License: Apache-2.0 Imports: 13 Imported by: 0

README

Build Status Go Report Card GoDoc

STATUS

flow is usable in its current state, even though it hasn't acquired all the desired functionality.

N.B. Those who intend to use flow should always use the most recent release. DO NOT use master!

flow

flow is a tiny open source (Apache 2-licensed) workflow engine written in Go (golang).

What flow is

As a workflow engine, flow intends to help in defining and driving "front office" <---> "back office" document flows. Examples of such flows are:

  • customer registration and verification of details,
  • assignment of work to field personnel, and its follow-up,
  • review and approval of documents, and
  • trouble ticket life cycle.

flow provides value in scenarios of type "programming in the large", though it is not (currently) distributed in nature. As such, it addresses only orchestration, not choreography!

flow - at least currently - aims to support only graph-like regimes (not hierarchical).

What flow is not

flow is a library, not a full-stack solution. Accordingly, it cannot be downloaded and deployed as a reday-to-use service. It has to be used by an application that programs workflow definitions and processing. The only "programming in the small" language supported is Go! Of course, you could employ flow in a microservice architecture by wrapping it in a thin service. That can enable you to use your favourite programming language to drive flow.

Express non-goals

flow is intended to be small! It is expressly not intended to be an enterprise-grade workflow engine. Accordingly, import from - and export to - workflow modelling formats like BPMN/XPDL are not supported. Similarly, executable specifications like BPEL and Wf-XML are not supported. True enterprise-grade engines already exist for addressing such complex workflows and interoperability as require high-end engines.

flow Concepts

Let us familiarise ourselves with the most important concepts and moving parts of flow. Even as you read the following, it is highly recommended that you read the database table definitions in sql directory, as well as the corresponding object definitions in their respective *.go files. That should help you in forming a mental model of flow faster.

Users

flow neither creates nor manages users. It assumes that an external identity provider is in charge of user management. Similarly, flow does not deal with user authentication, nor does it manage authorisation of tasks not flowing (pun intended) though it!

Accordingly, users in flow are represented only by their unique IDs, names and unique e-mail addresses. The identity provider has to also provide the status of the user: active vs. inactive.

Groups

flow, similar to most UNIXes, implicitly creates a group for each defined user. This is a singleton group: its only member is the corresponding user.

In addition, arbitrary general (non-singleton) groups can be defined by including one or more users as members. The relationship between users and groups is M:N.

Roles

Sets of document actions permitted for a given document type, can be grouped into roles. For instance, some users should be able to raise a request, but not approve it. Some others should be able to, in turn, approve or reject it. Roles make it convenient to group logically related sets of permissions.

See Document Types and Document Actions for more details.

Access Contexts

An access context is a namespace that defines jurisdictions of permissions granted to users and groups. Examples of such jurisdictions include departments, branches, cost centres and projects.

Within an access context, a given user (though the associated singleton group) or group can be assigned one or more roles. The effective set of permissions available to a user - in this access context - is the union of the permissions granted through all roles assigned to this user, through all groups the user is included in.

Document Types

Each type of document, whose workflow is managed by flow, has a unique DocType that is defined by the consuming application. Document types are one of the central concepts in flow. They serve as namespaces for several other types of entities.

A document type is just a string. flow does not assume anything about the specifics of any document type. Nonetheless, it is highly recommended, but not necessary, that document types be defined in a system of hierarchical namespaces. For example:

PUR:RFQ

could mean that the department is 'Purchasing', while the document type is 'Request For Quotation'. As a variant,

PUR:ORD

could mean that the document type is 'Purchase Order'.

Document States

Every document has various stages in its life. The possible stages in the life of a document are encoded as a set of DocStates specific to its document type.

A document state is just a string. flow does not assume anything about the specifics of any document state.

Document Actions

Given a document in a particular state, each legal (for that state) action on the document could result in a new state. DocActions enumerate possible actions that affect documents.

A document action is just a string. flow does not assume anything about the specifics of any document action.

Documents

A document comprises:

  • title,
  • body (usually, text),
  • enclosures/attachments (optional),
  • tags (optional) and
  • children documents (optional).

Thus, Document is a recursive structure. As a document transitions from state to state, a child document is created and attached to it. Thus, documents form a hierarchy, much like an e-mail thread, a discussion forum thread or a trouble ticket thread.

Only root documents have their own titles. Similarly, only root documents participate in workflows. Children documents follow their root documents along.

Workflows

Each DocType defined in flow should have an associated Workflow defined. This workflow handles the lifecycle of documents of that type.

A workflow is begun when a document of a particular type is created. This workflow then tracks the document as it transitions from one document state to another, in reponse to either user actions or system events. These document states and their transitions constitute the defining graph of this workflow.

Document Events

A DocEvent represents a user (or system) DocAction on a particular document that is in a particular DocState. They record the agent casuing them (system/which user), as well as the time when the action was performed.

Nodes

A document in a particular state in its workflow, is sent to a Node. There, it awaits an action to take place that moves it along the workflow, to a different state. Thus, nodes are receivers of document events.

A DocAction on a document in a DocState may require some processing to be performed before a possible state transition. Accordingly, applications can register custom processing functions with nodes. Such functions are invoked by the respective nodes when an action is received by them. These NodeFuncs generate the messages that are dispatched to applicable mailboxes.

Mailboxes and Messages

Every defined user has a Mailbox of virtually no size limit. Documents that transition into specific states trigger notifications for specific users. These notifications are delivered to the mailboxes of such users.

The actual content of a notification constitutes a Message. The most essential details include the document reference, the Node in the workflow at which the document is, and the time at which the message was sent.

Upon getting notified, users open the corresponding documents, and take appropriate actions.

Example Structure

The following is a simple example structure.

Document Type : docType1
Document States : [
    docState1, docState2, docState3, docState4 // for example
]
Document Actions : [
    docAction12, docAction23, docAction34 // for the above document states
]
Document Type State Transitions : [
    docState1 --docAction12--> docState2,
    docState2 --docAction23--> docState3,
    docState3 --docAction34--> docState4,
]

Access Contexts : [
    accCtx1, accCtx2 // for example
]

Workflow : {
    Name : wFlow1,
    Initial State : docState1
}
Nodes : [
    node1: {
        Document Type : docType1,
        Workflow : wFlow1,
        Node Type : NodeTypeBegin, // note this
        From State : docState1,
        Access Context : accCtx1,
    },
    node2: {
        Document Type : docType1,
        Workflow : wFlow1,
        Node Type : NodeTypeLinear, // note this
        From State : docState2,
        Access Context : accCtx2, // a different context
    },
    node3: {
        Document Type : docType1,
        Workflow : wFlow1,
        Node Type : NodeTypeEnd, // note this
        From State : docState3,
        Access Context : accCtx1,
    },
]

With the above setup, we can dispatch document events to the workflow appropriately. With each event, the workflow moves along, as defined.

Documentation

Overview

Package flow is a tiny workflow engine written in Go (golang).

Index

Constants

View Source
const (
	// ErrUnknown : unknown internal error
	ErrUnknown = Error("ErrUnknown : unknown internal error")

	// ErrDocEventRedundant : another equivalent event has already effected this action
	ErrDocEventRedundant = Error("ErrDocEventRedundant : another equivalent event has already applied this action")
	// ErrDocEventDocTypeMismatch : document's type does not match event's type
	ErrDocEventDocTypeMismatch = Error("ErrDocEventDocTypeMismatch : document's type does not match event's type")
	// ErrDocEventStateMismatch : document's state does not match event's state
	ErrDocEventStateMismatch = Error("ErrDocEventStateMismatch : document's state does not match event's state")
	// ErrDocEventAlreadyApplied : event already applied; nothing to do
	ErrDocEventAlreadyApplied = Error("ErrDocEventAlreadyApplied : event already applied; nothing to do")

	// ErrDocumentNoParent : document is a root document
	ErrDocumentNoParent = Error("ErrDocumentNoParent : document is a root document")
	// ErrDocumentIsChild : cannot have its own state, title or tags
	ErrDocumentIsChild = Error("ErrDocumentIsChild : cannot have its own state, title or tags")

	// ErrWorkflowInactive : this workflow is currently inactive
	ErrWorkflowInactive = Error("ErrWorkflowInactive : this workflow is currently inactive")
	// ErrWorkflowInvalidAction : given action cannot be performed on this document's current state
	ErrWorkflowInvalidAction = Error("ErrWorkflowInvalidAction : given action cannot be performed on this document's current state")

	// ErrMessageNoRecipients : list of recipients is empty
	ErrMessageNoRecipients = Error("ErrMessageNoRecipients : list of recipients is empty")
)
View Source
const (
	// NodeTypeBegin : none incoming, one outgoing
	NodeTypeBegin NodeType = "begin"
	// NodeTypeEnd : one incoming, none outgoing
	NodeTypeEnd = "end"
	// NodeTypeLinear : one incoming, one outgoing
	NodeTypeLinear = "linear"
	// NodeTypeBranch : one incoming, two or more outgoing
	NodeTypeBranch = "branch"
	// NodeTypeJoinAny : two or more incoming, one outgoing
	NodeTypeJoinAny = "joinany"
	// NodeTypeJoinAll : two or more incoming, one outgoing
	NodeTypeJoinAll = "joinall"
)

The following constants are represented **identically** as part of an enumeration in the database. DO NOT ALTER THESE WITHOUT ALSO ALTERING THE DATABASE; ELSE DATA COULD GET CORRUPTED!

View Source
const (
	// DefACRoleCount is the default number of roles a group can have
	// in an access context.
	DefACRoleCount = 1
)

Variables

View Source
var AccessContexts _AccessContexts

AccessContexts provides a resource-like interface to access contexts in the system.

View Source
var DocActions _DocActions

DocActions provides a resource-like interface to document actions in the system.

View Source
var DocEvents _DocEvents

DocEvents exposes a resource-like interface to document events.

View Source
var DocStates _DocStates

DocStates provides a resource-like interface to document actions in the system.

View Source
var DocTypes _DocTypes

DocTypes provides a resource-like interface to document types in the system.

View Source
var Documents _Documents

Documents provides a resource-like interface to the documents in this system.

View Source
var Groups _Groups

Groups provides a resource-like interface to groups in the system.

View Source
var Mailboxes _Mailboxes

Mailboxes is the singleton instance of `_Mailboxes`.

View Source
var Nodes _Nodes

Nodes provides a resource-like interface to the nodes defined in this system.

View Source
var Roles _Roles

Roles provides a resource-like interface to roles in the system.

View Source
var Users _Users

Users provides a resource-like interface to users in the system.

View Source
var Workflows _Workflows

Workflows provides a resource-like interface to the workflows defined in the system.

Functions

func IsValidNodeType

func IsValidNodeType(ntype string) bool

IsValidNodeType answers `true` if the given node type is a recognised node type in the system.

func RegisterDB

func RegisterDB(sdb *sql.DB) error

RegisterDB provides an already initialised database handle to `flow`.

N.B. This method **MUST** be called before anything else in `flow`.

func SetBlobsDir

func SetBlobsDir(base string) error

SetBlobsDir specifies the base directory inside which blob files should be stored.

Inside this base directory, 256 subdirectories are created as hex `00` through `ff`. A blob is stored in the subdirectory whose name matches the first two hex digits of its SHA1 sum.

N.B. Once set, this MUST NOT change between runs. Doing so will result in loss of all previously stored blobs. In addition, corresponding documents get corrupted.

Types

type AcGroup

type AcGroup struct {
	Group     `json:"Group"` // An assigned user
	ReportsTo Group          `json:"ReportsTo"` // Reporting authority of this user
}

AcGroup holds the information of a user together with the user's reporting authority.

type AcGroupRoles

type AcGroupRoles struct {
	Group string `json:"Group"` // Group whose roles this represents
	Roles []Role `json:"Roles"` // Map holds the role assignments to groups
}

AcGroupRoles holds the information of the various roles that each group has been assigned in this access context.

type AccessContext

type AccessContext struct {
	ID     AccessContextID `json:"ID"`               // Unique identifier of this access context
	Name   string          `json:"Name,omitempty"`   // Globally-unique namespace; can be a department, project, location, branch, etc.
	Active bool            `json:"Active,omitempty"` // Can a workflow be initiated in this context?
}

AccessContext is a namespace that provides an environment for workflow execution.

It is an environment in which users are mapped into a hierarchy that determines certain aspects of workflow control. This hierarchy, usually, but not necessarily, reflects an organogram. In each access context, applicable groups are mapped to their respective intended permissions. This mapping happens through roles.

Each workflow that operates on a document type is given an associated access context. This context is used to determine workflow routing, possible branching and rendezvous points.

Please note that the same workflow may operate independently in multiple unrelated access contexts. Thus, a workflow is not limited to one access context. Conversely, an access context can have several workflows operating on it, for various document types. Therefore, the relationship between workflows and access contexts is M:N.

For complex organisational requirements, the name of the access context can be made hierarchical with a suitable delimiter. For example:

  • IN:south:HYD:BR-101
  • sbu-08/client-0249/prj-006348

func (*AccessContext) GroupHasPermission

func (ac *AccessContext) GroupHasPermission(id AccessContextID, gid GroupID, dtype DocTypeID, action DocActionID) (bool, error)

GroupHasPermission answers `true` if the given group has the requested action enabled on the specified document type; `false` otherwise.

type AccessContextID

type AccessContextID int64

AccessContextID is the type unique access context identifiers.

type Blob

type Blob struct {
	Name    string `json:"Name"`           // User-given name to the binary object
	Path    string `json:"Path,omitempty"` // Path to the stored binary object
	SHA1Sum string `json:"SHA1sum"`        // SHA1 checksum of the binary object
}

Blob is a simple data holder for information concerning the user-supplied name of the binary object, the path of the stored binary object, and its SHA1 checksum.

type DocAction

type DocAction struct {
	ID        DocActionID `json:"ID"`        // Unique identifier of this action
	Name      string      `json:"Name"`      // Globally-unique name of this action
	Reconfirm bool        `json:"Reconfirm"` // Should the user be prompted for a reconfirmation of this action?
}

DocAction enumerates the types of actions in the system, as defined by the consuming application. Each document action has an associated workflow transition that it causes.

Accordingly, `flow` does not assume anything about the specifics of the any document action. Instead, it treats document actions as plain, but controlled, vocabulary. Good examples include:

CREATE,
REVIEW,
APPROVE,
REJECT,
COMMENT,
CLOSE, and
REOPEN.

N.B. All document actions must be defined as constant strings.

type DocActionID

type DocActionID int64

DocActionID is the type of unique identifiers of document actions.

type DocEvent

type DocEvent struct {
	ID      DocEventID  `json:"ID"`        // Unique ID of this event
	DocType DocTypeID   `json:"DocType"`   // Document type of the document to which this event is to be applied
	DocID   DocumentID  `json:"DocID"`     // Document to which this event is to be applied
	State   DocStateID  `json:"DocState"`  // Current state of the document must equal this
	Action  DocActionID `json:"DocAction"` // Action performed by the user
	Group   GroupID     `json:"Group"`     // Group (singleton) who caused this action
	Text    string      `json:"Text"`      // Comment or other content
	Ctime   time.Time   `json:"Ctime"`     // Time at which the event occurred
	Status  EventStatus `json:"Status"`    // Status of this event
}

DocEvent represents a user action performed on a document in the system.

Together with documents and nodes, events are central to the workflow engine in `flow`. Events cause documents to transition from one state to another, usually in response to user actions. It is possible for system events to cause state transitions, as well.

func (*DocEvent) StatusInDB

func (e *DocEvent) StatusInDB() (EventStatus, error)

StatusInDB answers the status of this event.

type DocEventID

type DocEventID int64

DocEventID is the type of unique document event identifiers.

type DocEventsListInput

type DocEventsListInput struct {
	DocTypeID                   // Events on documents of this type are listed
	AccessContextID             // Access context from within which to list
	GroupID                     // List events created by this (singleton) group
	DocStateID                  // List events acting on this state
	CtimeStarting   time.Time   // List events created after this time
	CtimeBefore     time.Time   // List events created before this time
	Status          EventStatus // List events that are in this state of application
}

DocEventsListInput specifies a set of filter conditions to narrow down document listings.

type DocEventsNewInput

type DocEventsNewInput struct {
	DocTypeID          // Type of the document; required
	DocumentID         // Unique identifier of the document; required
	DocStateID         // Document must be in this state for this event to be applied; required
	DocActionID        // Action performed by `Group`; required
	GroupID            // Group (user) who performed the action that raised this event; required
	Text        string // Any comments or notes; required
}

DocEventsNewInput holds information needed to create a new document event in the system.

type DocPath

type DocPath string

DocPath helps in managing document hierarchies. It provides a set of utility methods that ease path management.

func (*DocPath) Append

func (p *DocPath) Append(dtid DocTypeID, did DocumentID) error

Append adds the given document type-document ID pair to this path, updating it as a result.

func (*DocPath) Components

func (p *DocPath) Components() ([]struct {
	DocTypeID
	DocumentID
}, error)

Components answers a sequence of this path's components, in order.

func (*DocPath) Root

func (p *DocPath) Root() (DocTypeID, DocumentID, error)

Root answers the root document information.

type DocState

type DocState struct {
	ID   DocStateID `json:"ID"`             // Unique identifier of this document state
	Name string     `json:"Name,omitempty"` // Unique identifier of this state in its workflow
}

DocState is one of a set of enumerated states for a top-level document, as defined by the consuming application.

`flow`, therefore, does not assume anything about the specifics of any state. Applications can, for example, embed `DocState` in a struct that provides more context. Document states should be loaded during application initialisation.

N.B. A `DocState` once defined and used, should *NEVER* be removed. At best, it can be deprecated by defining a new one, and then altering the corresponding workflow definition to use the new one instead.

type DocStateID

type DocStateID int64

DocStateID is the type of unique identifiers of document states.

type DocType

type DocType struct {
	ID   DocTypeID `json:"ID,omitempty"`   // Unique identifier of this document type
	Name string    `json:"Name,omitempty"` // Unique name of this document type
}

DocType enumerates the types of documents in the system, as defined by the consuming application. Each document type has an associated workflow definition that drives its life cycle.

Accordingly, `flow` does not assume anything about the specifics of the any document type. Instead, it treats document types as plain, but controlled, vocabulary. Nonetheless, it is highly recommended, but not necessary, that document types be defined in a system of hierarchical namespaces. For example:

PUR:RFQ

could mean that the department is 'Purchasing', while the document type is 'Request For Quotation'. As a variant,

PUR:ORD

could mean that the document type is 'Purchase Order'.

N.B. All document types must be defined as constant strings.

type DocTypeID

type DocTypeID int64

DocTypeID is the type of unique identifiers of document types.

type Document

type Document struct {
	ID      DocumentID `json:"ID"`      // Globally-unique identifier of this document
	DocType DocType    `json:"DocType"` // For namespacing
	Path    DocPath    `json:"Path"`    // Path leading to, but not including, this document

	AccCtx AccessContext `json:"AccessContext"` // Originating access context of this document; applicable only to a root document
	State  DocState      `json:"DocState"`      // Current state of this document; applicable only to a root document

	Group Group     `json:"Group"` // Creator of this document
	Ctime time.Time `json:"Ctime"` // Creation time of this (possibly child) document

	Title string `json:"Title"`          // Human-readable title; applicable only for root documents
	Data  string `json:"Data,omitempty"` // Primary content of the document
}

Document represents a task in a workflow, whose life cycle it tracks.

Documents are central to the workflow engine and its operations. In the process, it accumulates various details, and tracks the times of its modifications. The life cycle typically involves several state transitions, whose details are also tracked.

`Document` is a recursive structure: it can contain other documents. Therefore, when a document is created, it is initialised with the path that leads from its root document to its immediate parent. For root documents, this path is empty.

Most applications should embed `Document` in their document structures rather than use this directly. That enables them to control their data persistence mechanisms, while delegating workflow management to `flow`.

type DocumentID

type DocumentID int64

DocumentID is the type of unique document identifiers.

type DocumentsListInput

type DocumentsListInput struct {
	DocTypeID                 // Documents of this type are listed; required
	AccessContextID           // Access context from within which to list; required
	GroupID                   // List documents created by this (singleton) group
	DocStateID                // List documents currently in this state
	CtimeStarting   time.Time // List documents created after this time
	CtimeBefore     time.Time // List documents created before this time
	TitleContains   string    // List documents whose title contains the given text; expensive operation
	RootOnly        bool      // List only root (top-level) documents
}

DocumentsListInput specifies a set of filter conditions to narrow down document listings.

type DocumentsNewInput

type DocumentsNewInput struct {
	DocTypeID                  // Type of the new document; required
	AccessContextID            // Access context in which the document should be created; required
	GroupID                    // (Singleton) group of the creator; required
	ParentType      DocTypeID  // Document type of the parent document, if any
	ParentID        DocumentID // Unique identifier of the parent document, if any
	Title           string     // Title of the new document; applicable to only root (top-level) documents
	Data            string     // Body of the new document; required
}

DocumentsNewInput specifies the initial data with which a new document has to be created in the system.

type Error

type Error string

Error defines `flow`-specific errors, and satisfies the `error` interface.

func (Error) Error

func (e Error) Error() string

Error implements the `error` interface.

type EventStatus

type EventStatus uint8

EventStatus enumerates the query parameter values for filtering by event state.

const (
	// EventStatusAll does not filter events.
	EventStatusAll EventStatus = iota
	// EventStatusApplied selects only those events that have been successfully applied.
	EventStatusApplied
	// EventStatusPending selects only those events that are pending application.
	EventStatusPending
)

type Group

type Group struct {
	ID        GroupID `json:"ID"`        // Globally-unique ID
	Name      string  `json:"Name"`      // Globally-unique name
	GroupType string  `json:"GroupType"` // Is this a user-specific group? Etc.
}

Group represents a specified collection of users. A user belongs to zero or more groups.

type GroupID

type GroupID int64

GroupID is the type of unique group identifiers.

type Mailbox

type Mailbox struct {
	GroupID `json:"GroupID"` // Group (or singleton user) owner of this mailbox
}

Mailbox is the message delivery destination for both action and informational messages.

Both users and groups have mailboxes. In all normal cases, a message is 'consumed' by the recipient. Messages can be moved into and out of mailboxes to facilitate reassignments under specific or extraordinary conditions.

type Message

type Message struct {
	ID      MessageID        `json:"ID"` // Globally-unique identifier of this message
	DocType `json:"DocType"` // Document type of the associated document
	DocID   DocumentID       `json:"DocID"`    // Document in the workflow
	Event   DocEventID       `json:"DocEvent"` // Event that triggered this message
	Title   string           `json:"Title"`    // Subject of this message
	Data    string           `json:"Data"`     // Body of this message
}

Message is the content part of a notification sent by the workflow engine to possibly multiple mailboxes.

Messages can be informational or seek action. Each message contains a reference to the document that began the current workflow, as well as the event that triggered this message.

type MessageID

type MessageID int64

MessageID is the type of unique identifiers of messages.

type Node

type Node struct {
	ID       NodeID          `json:"ID"`                      // Unique identifier of this node
	DocType  DocTypeID       `json:"DocType"`                 // Document type which this node's workflow manages
	State    DocStateID      `json:"DocState"`                // A document arriving at this node must be in this state
	AccCtx   AccessContextID `json:"AccessContext,omitempty"` // Specific access context associated with this state, if any
	Wflow    WorkflowID      `json:"Workflow"`                // Containing flow of this node
	Name     string          `json:"Name"`                    // Unique within its workflow
	NodeType NodeType        `json:"NodeType"`                // Topology type of this node
	// contains filtered or unexported fields
}

Node represents a specific logical unit of processing and routing in a workflow.

func (*Node) Func

func (n *Node) Func() NodeFunc

Func answers the processing function registered in this node definition.

func (*Node) SetFunc

func (n *Node) SetFunc(fn NodeFunc) error

SetFunc registers the given node function with this node.

If `nil` is given, a default node function is registered instead. This default function sets the document title as the message subject, and the event's data as the message body.

func (*Node) Transitions

func (n *Node) Transitions() (map[DocActionID]DocStateID, error)

Transitions answers the possible document states into which a document currently in the given state can transition.

type NodeFunc

type NodeFunc func(*Document, *DocEvent) *Message

NodeFunc defines the type of functions that generate notification messages in workflows.

These functions are triggered by appropriate nodes, when document events are applied to documents to possibly transform them. Invocation of a `NodeFunc` should result in a message that can then be dispatched to applicable mailboxes.

Error should be returned only when an impossible situation arises, and processing needs to abort. Note that returning an error stops the workflow. Manual intervention will be needed to move the document further.

N. B. NodeFunc instances must be referentially transparent -- stateless and not capture their environment in any manner. Unexpected bad things could happen otherwise!

type NodeID

type NodeID int64

NodeID is the type of unique identifiers of nodes.

type NodeType

type NodeType string

NodeType enumerates the possible types of workflow nodes.

type Notification

type Notification struct {
	GroupID `json:"Group"`   // The group whose mailbox this notification is in
	Message `json:"Message"` // The underlying message
	Unread  bool             `json:"Unread"` // Status flag reflecting if the message is still not read
	Ctime   time.Time        `json:"Ctime"`  // Time when this notification was posted
}

Notification tracks the 'unread' status of a message in a mailbox.

Since a single message can be delivered to multiple mailboxes, the 'unread' status cannot be associated with a message. Instead, `Notification` is the entity that tracks it per mailbox.

type Role

type Role struct {
	ID   RoleID `json:"ID"`   // globally-unique ID of this role
	Name string `json:"Name"` // name of this role
}

Role represents a collection of privileges.

Each group in the system can have one or more roles assigned.

type RoleID

type RoleID int64

RoleID is the type of unique role identifiers.

type Transition

type Transition struct {
	Upon DocAction // If user/system has performed this action
	To   DocState  // Document transitions into this state
}

Transition holds the information of which action results in which state.

type TransitionMap

type TransitionMap struct {
	From        DocState // When document is in this state
	Transitions map[DocActionID]Transition
}

TransitionMap holds the state transitions defined for this document type. It lays out which actions result in which target states, given current states.

type User

type User struct {
	ID        UserID `json:"ID"`               // Must be globally-unique
	FirstName string `json:"FirstName"`        // For display purposes only
	LastName  string `json:"LastName"`         // For display purposes only
	Email     string `json:"Email"`            // E-mail address of this user
	Active    bool   `json:"Active,omitempty"` // Is this user account active?
}

User represents any kind of a user invoking or otherwise participating in a defined workflow in the system.

User details are expected to be provided by an external identity provider application or directory. `flow` neither defines nor manages users.

type UserID

type UserID int64

UserID is the type of unique user identifiers.

type Workflow

type Workflow struct {
	ID         WorkflowID `json:"ID,omitempty"`     // Globally-unique identifier of this workflow
	Name       string     `json:"Name,omitempty"`   // Globally-unique name of this workflow
	DocType    DocType    `json:"DocType"`          // Document type of which this workflow defines the life cycle
	BeginState DocState   `json:"BeginState"`       // Where this flow begins
	Active     bool       `json:"Active,omitempty"` // Is this workflow enabled?
}

Workflow represents the entire life cycle of a single document.

A workflow begins with the creation of a document, and drives its life cycle through a sequence of responses to user actions or other system events.

The engine in `flow` is visible primarily through workflows, documents and their behaviour.

Currently, the topology of workflows is a graph, and is determined by the node definitions herein.

N.B. It is highly recommended, but not necessary, that workflow names be defined in a system of hierarchical namespaces.

func (*Workflow) ApplyEvent

func (w *Workflow) ApplyEvent(otx *sql.Tx, event *DocEvent, recipients []GroupID) (DocStateID, error)

ApplyEvent takes an input user action or a system event, and applies its document action to the given document. This results in a possibly new document state. This method also prepares a message that is posted to applicable mailboxes.

type WorkflowID

type WorkflowID int64

WorkflowID is the type of unique workflow identifiers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL