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, variablesruns: Collection of execution runs created from this proceduretasks: Collection of tasks created for runsrunInstances: Links between runs and instances
Commands and Operations:
| Command | Triggered By | Purpose | Business Logic |
|---|---|---|---|
createWorkflow() | Human (Admin/Developer) | Create new workflow definition | Creates Procedure with Workflow entity, emits ProcedureCreatedEvent |
updateWorkflowDetails() | Human (Admin/Developer) | Update workflow configuration | Updates workflow properties, emits ProcedureUpdatedEvent |
deleteWorkflow() | Human (Admin) | Soft-delete workflow | Marks workflow as deleted, emits WorkflowDeletedEvent |
addVariable() | Human (Admin/Developer) | Add workflow variable | Adds variable to workflow, emits ProcedureUpdatedEvent |
updateVariable() | Human (Admin/Developer) | Update variable name | Updates variable, emits ProcedureUpdatedEvent |
removeVariable() | Human (Admin/Developer) | Remove workflow variable | Removes variable, emits ProcedureUpdatedEvent |
createRun() | Human (User) or System (Automated trigger) | Create execution run with tasks | Creates Run and associated Tasks, emits RunCreatedEvent and TaskCreatedEvent |
updateRunStatus() | System (Execution domain) | Update run execution status | Updates run status, emits RunUpdatedEvent |
linkInstanceToRun() | System (Resource domain) | Link instance to run | Creates RunInstance link, emits InstanceLinkedToRunEvent |
deleteRun() | Human (Admin) | Delete run | Soft-deletes run, emits RunDeletedEvent |
assignTaskToInstance() | System (Task assignment logic) | Assign task to instance | Assigns task to instance, updates task status |
updateTaskStatus() | System (Execution domain) | Update task status | Updates task status |
c. Domain Entry Points
The Procedure aggregate provides static factory methods that serve as entry points for creating new instances:
| Static Command | Triggered By | Purpose |
|---|---|---|
createWorkflow() | Human (Admin/Developer) | Creates new Procedure aggregate with Workflow entity |
👉 All workflow creation commands emit the ProcedureCreatedEvent
Key Aggregate Invariants:
- Workflow Ownership: Each Procedure owns exactly one Workflow entity
- Run-Task Relationship: Tasks belong to exactly one Run, which belongs to one Procedure
- Variable Scope: Variables belong to the Workflow and are scoped to the Procedure
- Instance Definition Requirement: Workflow must have
instanceDefinitionIdbefore 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:
| State | Description | Indicates |
|---|---|---|
| Task PENDING | Task created, waiting for execution | Ready to be assigned to instance |
| Task IN_PROGRESS | Task assigned and executing | Currently being processed |
| Task COMPLETED | Task finished successfully | Execution completed |
| Task FAILED | Task execution failed | Execution encountered errors |
| Attempt PENDING | Attempt created, waiting to start | Ready to begin execution |
| Attempt IN_PROGRESS | Attempt actively executing | Commands being executed |
| Attempt COMPLETED | Attempt finished successfully | All commands completed |
| Attempt FAILED | Attempt execution failed | Execution encountered errors |
| Attempt CANCELED | Attempt canceled | Execution canceled by user/system |
| Command PENDING | Command created, waiting execution | Ready to execute |
| Command IN_PROGRESS | Command executing | Currently being processed |
| Command COMPLETED | Command finished successfully | Command executed successfully |
| Command FAILED | Command execution failed | Command 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:
| Command | Triggered By | From States | To State | Business Rules |
|---|---|---|---|---|
createAttempt() | System (Task assignment) | - | Attempt PENDING | Creates new attempt for instance |
findOrCreateAttemptForInstance() | System (Task assignment) | - | Attempt PENDING | Reuses existing PENDING attempt or creates new |
markAttemptInProgress() | System (Execution start) | Attempt PENDING | Attempt IN_PROGRESS | Sets startedAt timestamp |
updateAttempt() | System (State updates) | Any | Any | Updates attempt state/status |
completeTask() | System (Execution completion) | Attempt IN_PROGRESS | Attempt COMPLETED, Task COMPLETED | Sets completedAt timestamp, emits TaskCompletedEvent |
createCommand() | System (AI/Execution logic) | Attempt IN_PROGRESS | Command PENDING | Creates command with optional reasoning, emits CommandCreatedEvent |
updateCommand() | System (Command execution) | Command PENDING | Command IN_PROGRESS | Updates command state |
markCommandAsFailed() | System (Error handling) | Command PENDING, IN_PROGRESS | Command FAILED | Records error, emits CommandFailedEvent |
handleCommandFailure() | System (Error handling) | Command PENDING, IN_PROGRESS | Command FAILED | Formats 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 Method | Purpose | Triggered By |
|---|---|---|
createFromTask() | Initialize Execution aggregate from Task | TaskCreatedEvent 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
↓
TERMINATINGEC2 Instance State Machine:
PENDING → RUNNING → STOPPED → DELETEDState Definitions:
| State | Description | Indicates |
|---|---|---|
| STARTING | Instance initializing | EC2 instance starting, not ready for work |
| IDLE | Instance running but not doing work | Ready to accept tasks |
| ACTIVE | Instance currently executing task | Processing attempt |
| PAUSED | Instance temporarily stopped | Paused by user/system |
| ERROR | Instance encountered exception | Error state, may recover |
| RECOVERING | Instance handling error | Attempting to recover from error |
| STOPPED | Instance shut down gracefully | Stopped cleanly |
| CRASHED | Instance stopped unexpectedly | Unexpected termination |
| DELETED | Instance marked for deletion | Soft-deleted |
| TERMINATING | Instance being terminated | Termination in progress |
Internal Commands and State Transitions:
| Command | Triggered By | From States | To State | Business Rules |
|---|---|---|---|---|
createFromInstanceDefinition() | Human (Admin) | - | - | Creates Resource aggregate from definition |
startInstance() | Human (Admin) or System (Auto-scaling) | - | Instance STARTING | Creates new instance, emits InstanceStartedEvent |
handleInstanceStarted() | System (AWS EC2 event) | Instance STARTING | Instance IDLE | Marks instance as ready, emits InstanceBecameIdleEvent |
handleInstanceStopped() | System (AWS EC2 event) | Instance RUNNING | Instance STOPPED | Marks instance as stopped |
handleInstanceFailed() | System (Error detection) | Instance ACTIVE, IDLE | Instance ERROR | Marks instance as failed |
assignInstanceToAttempt() | System (Task assignment) | Instance IDLE | Instance ACTIVE | Assigns attempt to instance, emits InstanceTaskAssignedEvent |
instanceCompleteTask() | System (Task completion) | Instance ACTIVE | Instance IDLE | Clears currentAttemptId, emits InstanceTaskCompletedEvent |
terminateInstance() | Human (Admin) or System (Auto-scaling) | Instance IDLE, ACTIVE | Instance TERMINATING | Terminates instance, emits InstanceTerminatedEvent |
deleteInstance() | Human (Admin) | Instance STOPPED, CRASHED | Instance DELETED | Soft-deletes instance (must be stopped/crashed) |
updateEc2InstanceStatus() | System (AWS EC2 status sync) | Any EC2 state | Any EC2 state | Syncs EC2 status, maps to Instance status |
didStartServerInstance() | System (EC2 instance started) | - | EC2 PENDING | Records EC2 instance creation |
didTerminateServerInstance() | System (EC2 instance terminated) | EC2 RUNNING | EC2 STOPPED | Records 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 Method | Purpose | Triggered By |
|---|---|---|
createFromInstanceDefinition() | Initialize Resource aggregate from InstanceDefinition | InstanceDefinition 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