Skip to content

Lifecycle States

State machines for each domain with allowed transitions. Terminal states have no outbound transitions. Transition methods validate allowed moves and fire middag/{domain}/status_changed events.

Entitlement

FromAllowed To
activesuspended, expired, cancelled
suspendedactive, cancelled
expiredactive, cancelled
cancelled(terminal)

Quote

FromAllowed To
draftsent, cancelled
sentviewed, accepted, rejected, expired
viewedaccepted, rejected, expired
acceptedpaid, cancelled
paidfulfilled
fulfilled(terminal)
rejected(terminal)
expired(terminal)
cancelled(terminal)

Environment

FromAllowed To
provisioningactive, cancelled
activemaintenance, suspended, decommissioned
maintenanceactive
suspendedactive, decommissioned
decommissioned(terminal)

Service

Defined in ServiceStatus enum with allowedTransitions():

FromAllowed To
proposalapproved, cancelled
approvedin_progress, cancelled
in_progresson_hold, delivered, cancelled
on_holdin_progress, cancelled
deliveredclosed, in_progress
closed(terminal)
cancelled(terminal)

Ticket

Defined in TicketStatus enum with allowedTransitions():

FromAllowed To
openin_progress, waiting, cancelled
in_progresswaiting, resolved, cancelled
waitingin_progress, cancelled
resolvedclosed, in_progress
closed(terminal)
cancelled(terminal)

Contract

FromAllowed To
draftactive, cancelled
activesuspended, expired, renewed, cancelled
suspendedactive, cancelled
expiredrenewed
renewed(terminal)
cancelled(terminal)

Transition Enforcement

Status transitions are validated in domain services before persistence:

php
// ServiceStatus enum
public function allowedTransitions(): array
{
    return match ($this) {
        self::Proposal => ['approved', 'cancelled'],
        self::Approved => ['in_progress', 'cancelled'],
        // ...
        self::Closed => [],
        self::Cancelled => [],
    };
}

Invalid transitions throw InvalidArgumentException. The status_changed event fires only after a successful transition.