Skip to content

Screenflow Service - Domain Design

1. Procedure sub-domain

Aggregate Root: Procedure

a. Description

The Procedure domain represents the design-time definition of work—a workflow template that defines how tasks should be executed. It encapsulates a Workflow entity that contains the configuration, variables, and metadata needed to execute RPA (Robotic Process Automation) workflows.

The Procedure aggregate orchestrates the creation and management of workflow definitions, runs, and tasks while maintaining consistency across the workflow lifecycle.

Key Properties:

  • workflow: The workflow entity containing name, description, mainPrompt, instanceDefinitionId, variables
  • runs: Collection of execution runs created from this procedure
  • tasks: Collection of tasks created for runs
  • runInstances: Links between runs and instances

Commands and Operations:

CommandTriggered ByPurposeBusiness Logic
createWorkflow()Human (Admin/Developer)Create new workflow definitionCreates Procedure with Workflow entity, emits ProcedureCreatedEvent
updateWorkflowDetails()Human (Admin/Developer)Update workflow configurationUpdates workflow properties, emits ProcedureUpdatedEvent
deleteWorkflow()Human (Admin)Soft-delete workflowMarks workflow as deleted, emits WorkflowDeletedEvent
addVariable()Human (Admin/Developer)Add workflow variableAdds variable to workflow, emits ProcedureUpdatedEvent
updateVariable()Human (Admin/Developer)Update variable nameUpdates variable, emits ProcedureUpdatedEvent
removeVariable()Human (Admin/Developer)Remove workflow variableRemoves variable, emits ProcedureUpdatedEvent
createRun()Human (User) or System (Automated trigger)Create execution run with tasksCreates Run and associated Tasks, emits RunCreatedEvent and TaskCreatedEvent
updateRunStatus()System (Execution domain)Update run execution statusUpdates run status, emits RunUpdatedEvent
linkInstanceToRun()System (Resource domain)Link instance to runCreates RunInstance link, emits InstanceLinkedToRunEvent
deleteRun()Human (Admin)Delete runSoft-deletes run, emits RunDeletedEvent
assignTaskToInstance()System (Task assignment logic)Assign task to instanceAssigns task to instance, updates task status
updateTaskStatus()System (Execution domain)Update task statusUpdates task status

c. Domain Entry Points

The Procedure aggregate provides static factory methods that serve as entry points for creating new instances:

Static CommandTriggered ByPurpose
createWorkflow()Human (Admin/Developer)Creates new Procedure aggregate with Workflow entity

👉 All workflow creation commands emit the ProcedureCreatedEvent

Key Aggregate Invariants:

  1. Workflow Ownership: Each Procedure owns exactly one Workflow entity
  2. Run-Task Relationship: Tasks belong to exactly one Run, which belongs to one Procedure
  3. Variable Scope: Variables belong to the Workflow and are scoped to the Procedure
  4. Instance Definition Requirement: Workflow must have instanceDefinitionId before creating runs

d. Domain Boundaries and Vision

Procedure owns workflow definitions and execution planning while remaining unaware of runtime execution details or resource management. Its job is to expose commands and events that other domains consume to drive workflows.

Integration boundaries

  • ↔ Execution Domain: Procedure emits RunCreatedEvent and TaskCreatedEvent when runs/tasks are created. Execution domain subscribes to these events to create Execution aggregates. Execution domain emits TaskCompletedEvent that Procedure consumes to update run/task status.
  • ↔ Resource Domain: Procedure emits RunCreatedEvent with instanceDefinitionId. Resource domain listens to create/assign instances. Resource domain emits InstanceTaskAssignedEvent that Procedure consumes to link instances to runs.
  • ← External Systems: External systems trigger workflow execution via ExecuteWorkflowUseCase, which creates runs and tasks through Procedure aggregate.

Vision

  • Procedure supports multi-tenant workflows with tenant isolation at the workflow level
  • Workflows can be versioned and updated without affecting running executions
  • Procedure maintains audit trail through domain events for all workflow lifecycle changes

2. Execution sub-domain

Aggregate Root: Execution

a. Description

The Execution domain represents the runtime instance of a procedure—a concrete execution of a workflow task. It orchestrates the execution lifecycle, managing attempts, commands, snapshots, and screenshots while maintaining execution state consistency.

Core Responsibility: Coordinate task execution attempts, manage command execution (CLICK, WRITE, WAIT, SNAPSHOT, FINISH), track execution progress through state machine, capture execution artifacts (snapshots, screenshots, reasoning), and emit execution events—while maintaining a clear audit trail of execution state and artifacts.

Key Principle: Execution acts as a runtime orchestrator that consumes tasks from the Procedure domain and produces execution artifacts and completion events. It manages the state machine progression of attempts and commands.

b. Current states & commands

The Execution aggregate manages state machines for both Tasks and Attempts:

Task State Machine:

PENDING → IN_PROGRESS → [COMPLETED | FAILED]

Attempt State Machine:

PENDING → IN_PROGRESS → [COMPLETED | FAILED | CANCELED]

Command State Machine:

PENDING → IN_PROGRESS → [COMPLETED | FAILED]

State Definitions:

StateDescriptionIndicates
Task PENDINGTask created, waiting for executionReady to be assigned to instance
Task IN_PROGRESSTask assigned and executingCurrently being processed
Task COMPLETEDTask finished successfullyExecution completed
Task FAILEDTask execution failedExecution encountered errors
Attempt PENDINGAttempt created, waiting to startReady to begin execution
Attempt IN_PROGRESSAttempt actively executingCommands being executed
Attempt COMPLETEDAttempt finished successfullyAll commands completed
Attempt FAILEDAttempt execution failedExecution encountered errors
Attempt CANCELEDAttempt canceledExecution canceled by user/system
Command PENDINGCommand created, waiting executionReady to execute
Command IN_PROGRESSCommand executingCurrently being processed
Command COMPLETEDCommand finished successfullyCommand executed successfully
Command FAILEDCommand execution failedCommand encountered errors

Command Types:

  • CLICK: Click action on UI element
  • WRITE: Type text into input field
  • WAIT: Wait for condition or timeout
  • SNAPSHOT: Capture screenshot of current state
  • FINISH: Complete execution

Internal Commands and State Transitions:

CommandTriggered ByFrom StatesTo StateBusiness Rules
createAttempt()System (Task assignment)-Attempt PENDINGCreates new attempt for instance
findOrCreateAttemptForInstance()System (Task assignment)-Attempt PENDINGReuses existing PENDING attempt or creates new
markAttemptInProgress()System (Execution start)Attempt PENDINGAttempt IN_PROGRESSSets startedAt timestamp
updateAttempt()System (State updates)AnyAnyUpdates attempt state/status
completeTask()System (Execution completion)Attempt IN_PROGRESSAttempt COMPLETED, Task COMPLETEDSets completedAt timestamp, emits TaskCompletedEvent
createCommand()System (AI/Execution logic)Attempt IN_PROGRESSCommand PENDINGCreates command with optional reasoning, emits CommandCreatedEvent
updateCommand()System (Command execution)Command PENDINGCommand IN_PROGRESSUpdates command state
markCommandAsFailed()System (Error handling)Command PENDING, IN_PROGRESSCommand FAILEDRecords error, emits CommandFailedEvent
handleCommandFailure()System (Error handling)Command PENDING, IN_PROGRESSCommand FAILEDFormats error, continues execution (command fails but task continues)
createSnapshot()System (Screenshot capture)Attempt IN_PROGRESS-Creates snapshot with screenshot, links to command
addReasoningToCommand()System (AI reasoning)Command PENDING, IN_PROGRESS-Adds reasoning text to command

Key Aggregate Properties:

  • id: Unique identifier (same as task.id)
  • task: The task being executed
  • attempts: Collection of execution attempts (can have multiple for retries)
  • updatedAt: Last modification timestamp

c. Domain Entry Points

The Execution aggregate provides a static factory method as its entry point:

Static MethodPurposeTriggered By
createFromTask()Initialize Execution aggregate from TaskTaskCreatedEvent consumption

d. Domain Boundaries and Vision

The Execution domain serves as a runtime orchestrator for task execution, consuming tasks from the Procedure domain and producing execution artifacts and completion events.

Integration Boundaries

← Procedure Domain:

  • Consumes: Tasks via TaskCreatedEvent
  • Boundary: Never manipulates Procedure state; only reads task definitions

→ Procedure Domain:

  • Produces: Task completion via TaskCompletedEvent
  • Triggers: Task status updates through Procedure.updateTaskStatus()

← Resource Domain:

  • Consumes: Instance availability via InstanceBecameIdleEvent
  • Boundary: Never manipulates Resource state; only reads instance availability

→ Resource Domain:

  • Produces: Instance task assignment via InstanceTaskAssignedEvent (handled by Resource domain)
  • Triggers: Instance activation through Resource.assignInstanceToAttempt()

← External Systems:

  • Consumes: Command execution requests from AI/automation systems
  • Produces: Execution artifacts (snapshots, screenshots, reasoning) for external consumption

Vision

  • Execution supports retry logic through multiple attempts per task
  • Command failures don't stop task execution (resilient execution model)
  • Execution maintains complete audit trail through snapshots and reasoning
  • Execution supports AI-driven command generation with reasoning capture

3. Resource sub-domain

Aggregate Root: Resource

a. Description

The Resource domain represents instances performing the execution—the compute resources (browser instances, EC2 instances) that execute workflow tasks. It manages the lifecycle of instance definitions and runtime instances, handling instance provisioning, assignment, and termination.

Core Responsibility: Manage instance definitions (templates), create and manage runtime instances, handle EC2 instance lifecycle, assign instances to tasks, track instance state machine, and emit resource events—while maintaining instance availability and health.

Key Principle: Resource acts as a resource manager that provides compute capacity for workflow execution. It manages both logical instances (domain concept) and physical EC2 instances (infrastructure).

b. Current states & commands

The Resource aggregate manages state machines for both Instance Definitions and Instances:

Instance State Machine:

STARTING → IDLE → ACTIVE → IDLE
    ↓        ↓       ↓        ↓
  ERROR   PAUSED  ERROR   STOPPED
    ↓        ↓       ↓        ↓
RECOVERING  ...   RECOVERING CRASHED

                           DELETED

                          TERMINATING

EC2 Instance State Machine:

PENDING → RUNNING → STOPPED → DELETED

State Definitions:

StateDescriptionIndicates
STARTINGInstance initializingEC2 instance starting, not ready for work
IDLEInstance running but not doing workReady to accept tasks
ACTIVEInstance currently executing taskProcessing attempt
PAUSEDInstance temporarily stoppedPaused by user/system
ERRORInstance encountered exceptionError state, may recover
RECOVERINGInstance handling errorAttempting to recover from error
STOPPEDInstance shut down gracefullyStopped cleanly
CRASHEDInstance stopped unexpectedlyUnexpected termination
DELETEDInstance marked for deletionSoft-deleted
TERMINATINGInstance being terminatedTermination in progress

Internal Commands and State Transitions:

CommandTriggered ByFrom StatesTo StateBusiness Rules
createFromInstanceDefinition()Human (Admin)--Creates Resource aggregate from definition
startInstance()Human (Admin) or System (Auto-scaling)-Instance STARTINGCreates new instance, emits InstanceStartedEvent
handleInstanceStarted()System (AWS EC2 event)Instance STARTINGInstance IDLEMarks instance as ready, emits InstanceBecameIdleEvent
handleInstanceStopped()System (AWS EC2 event)Instance RUNNINGInstance STOPPEDMarks instance as stopped
handleInstanceFailed()System (Error detection)Instance ACTIVE, IDLEInstance ERRORMarks instance as failed
assignInstanceToAttempt()System (Task assignment)Instance IDLEInstance ACTIVEAssigns attempt to instance, emits InstanceTaskAssignedEvent
instanceCompleteTask()System (Task completion)Instance ACTIVEInstance IDLEClears currentAttemptId, emits InstanceTaskCompletedEvent
terminateInstance()Human (Admin) or System (Auto-scaling)Instance IDLE, ACTIVEInstance TERMINATINGTerminates instance, emits InstanceTerminatedEvent
deleteInstance()Human (Admin)Instance STOPPED, CRASHEDInstance DELETEDSoft-deletes instance (must be stopped/crashed)
updateEc2InstanceStatus()System (AWS EC2 status sync)Any EC2 stateAny EC2 stateSyncs EC2 status, maps to Instance status
didStartServerInstance()System (EC2 instance started)-EC2 PENDINGRecords EC2 instance creation
didTerminateServerInstance()System (EC2 instance terminated)EC2 RUNNINGEC2 STOPPEDRecords EC2 instance termination

Key Aggregate Properties:

  • id: Unique identifier (same as instanceDefinition.id)
  • instanceDefinition: Template for creating instances
  • instances: Collection of runtime instances
  • ec2Instances: Collection of EC2 infrastructure instances
  • updatedAt: Last modification timestamp

c. Domain Entry Points

The Resource aggregate provides a static factory method as its entry point:

Static MethodPurposeTriggered By
createFromInstanceDefinition()Initialize Resource aggregate from InstanceDefinitionInstanceDefinition creation

d. Domain Boundaries and Vision

The Resource domain serves as a resource manager that provides compute capacity for workflow execution, managing both logical instances and physical infrastructure.

Integration Boundaries

← Procedure Domain:

  • Consumes: RunCreatedEvent with instanceDefinitionId
  • Boundary: Never manipulates Procedure state; only reads instance requirements

→ Procedure Domain:

  • Produces: Instance availability through InstanceBecameIdleEvent
  • Triggers: Instance linking through Procedure.linkInstanceToRun()

← Execution Domain:

  • Consumes: Instance availability requests
  • Boundary: Never manipulates Execution state; only provides instance assignment

→ Execution Domain:

  • Produces: Instance assignment via InstanceTaskAssignedEvent
  • Triggers: Attempt creation through Execution.createAttempt()

← AWS EC2:

  • Consumes: EC2 instance lifecycle events (started, stopped, terminated)
  • Boundary: Syncs EC2 state but doesn't control EC2 directly

→ AWS EC2:

  • Produces: EC2 instance creation/termination requests (via infrastructure adapters)
  • Triggers: EC2 instance lifecycle through infrastructure services

Vision

  • Resource supports auto-scaling based on task queue depth
  • Resource maintains instance health through error detection and recovery
  • Resource supports multi-tenant instance isolation
  • Resource provides instance pooling and reuse for efficiency
  • Resource maintains complete audit trail of instance lifecycle through domain events