diff --git a/website/docs/operations/01-run-code.mdx b/website/docs/operations/01-run-code.mdx
index 3798fb72..f9b8f770 100644
--- a/website/docs/operations/01-run-code.mdx
+++ b/website/docs/operations/01-run-code.mdx
@@ -39,7 +39,7 @@ These operations need special handling because they shouldn't be re-executed dur
:::info
-Workflows4s currently supports onyl cats-effect IO. If you're interested in other effect systems, please check [here](https://github.com/business4s/workflows4s/issues/59).
+Workflows4s currently supports only cats-effect IO. If you're interested in other effect systems, please check [here](https://github.com/business4s/workflows4s/issues/59).
:::
@@ -69,3 +69,10 @@ You can add descriptions to RunIO operations to provide additional context in di
```
+
+## Drafting support
+
+Executing logic comes with [drafting support](20-drafting.mdx).
+
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftStepExample.scala start=start_doc end=end_doc
+```
diff --git a/website/docs/operations/02-await-signal.mdx b/website/docs/operations/02-await-signal.mdx
index 13fcea15..1ae2c484 100644
--- a/website/docs/operations/02-await-signal.mdx
+++ b/website/docs/operations/02-await-signal.mdx
@@ -9,6 +9,15 @@ Signal handling is essential for workflows that need to pause and wait for exter
+## Drafting Support
+
+Awaiting signals come with [drafting support](20-drafting.mdx).
+
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftSignalExample.scala start=start_draft end=end_draft
+```
+
+
+
# Unhandled Signals
The Workflows4s API allows arbitrary signals to be sent to a workflow instance. While this provides flexibility, it also
diff --git a/website/docs/operations/02.1-timers.mdx b/website/docs/operations/02.1-timers.mdx
index 2c6cd504..218a6ad8 100644
--- a/website/docs/operations/02.1-timers.mdx
+++ b/website/docs/operations/02.1-timers.mdx
@@ -12,3 +12,12 @@ This operation enables time-based coordination, allowing workflows to pause for
```
+
+## Drafting Support
+
+Awaiting time comes with [drafting support](20-drafting.mdx).
+
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftTimerExample.scala start=start_draft end=end_draft
+```
+
+
diff --git a/website/docs/operations/03-sequence-operations.mdx b/website/docs/operations/03-sequence-operations.mdx
index 5c50153b..a867143f 100644
--- a/website/docs/operations/03-sequence-operations.mdx
+++ b/website/docs/operations/03-sequence-operations.mdx
@@ -28,3 +28,7 @@ Dynamic steps cannot be rendered statically. Consider using [Forks](/docs/operat
```
+
+## Drafting Support
+
+For Sequencing Operations, no dedicated draft API is required. Drafting can be done using the standard API.
diff --git a/website/docs/operations/04-handle-errors.mdx b/website/docs/operations/04-handle-errors.mdx
index 60851d65..407212b5 100644
--- a/website/docs/operations/04-handle-errors.mdx
+++ b/website/docs/operations/04-handle-errors.mdx
@@ -12,3 +12,7 @@ Errors defined and handled should be domain errors and not technical ones. Domai
```
+
+## Drafting Support
+
+For Error Handling, no dedicated draft API is required. Drafting can be done using the standard API.
diff --git a/website/docs/operations/9-for-each.mdx b/website/docs/operations/05-for-each.mdx
similarity index 96%
rename from website/docs/operations/9-for-each.mdx
rename to website/docs/operations/05-for-each.mdx
index b391e51d..3bd279b3 100644
--- a/website/docs/operations/9-for-each.mdx
+++ b/website/docs/operations/05-for-each.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 9.1
+sidebar_position: 5.1
---
import OperationOutputs from '@site/src/components/OperationOutputs';
@@ -23,9 +23,9 @@ This element is one of the most complicated ones and requires you to configure q
-### Draft Mode
+## Drafting Support
-For quick prototyping, you can use the draft API:
+Iterating comes with [drafting support](20-drafting.mdx).
```scala file=./main/scala/workflows4s/example/docs/ForEachExample.scala start=draft_start end=draft_end
```
diff --git a/website/docs/operations/05-loops.mdx b/website/docs/operations/05-loops.mdx
index 3c273cbf..a1fbcaa4 100644
--- a/website/docs/operations/05-loops.mdx
+++ b/website/docs/operations/05-loops.mdx
@@ -17,3 +17,12 @@ In the future this will be detected by the [linter](https://github.com/business4
```
+
+## Drafting Support
+
+Loops come with [drafting support](20-drafting.mdx).
+
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftLoopExample.scala start=start_draft end=end_draft
+```
+
+
diff --git a/website/docs/operations/06-fork.mdx b/website/docs/operations/06-fork.mdx
index 52ebefbd..980ea701 100644
--- a/website/docs/operations/06-fork.mdx
+++ b/website/docs/operations/06-fork.mdx
@@ -9,3 +9,12 @@ It's equivalent to `if` instructions but allow for static rendering of the workf
```
+
+## Drafting Support
+
+Branching comes with [drafting support](20-drafting.mdx).
+
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftForkExample.scala start=start_draft end=end_draft
+```
+
+
\ No newline at end of file
diff --git a/website/docs/operations/07-Interrupting.mdx b/website/docs/operations/07-Interrupting.mdx
index c2256f22..02c4fcd0 100644
--- a/website/docs/operations/07-Interrupting.mdx
+++ b/website/docs/operations/07-Interrupting.mdx
@@ -9,3 +9,12 @@ This allows selecting an alternative path based on such a signal.
```
+
+## Drafting Support
+
+Interruptions come with [drafting support](20-drafting.mdx).
+
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftInterruptionExample.scala start=start_draft end=end_draft
+```
+
+
\ No newline at end of file
diff --git a/website/docs/operations/08-parallel.mdx b/website/docs/operations/08-parallel.mdx
index a923697e..21e33db4 100644
--- a/website/docs/operations/08-parallel.mdx
+++ b/website/docs/operations/08-parallel.mdx
@@ -12,4 +12,13 @@ Workflow's state is continously updated after each step completion (doesn't wait
```scala file=./main/scala/workflows4s/example/docs/ParallelExample.scala start=start_doc end=end_doc
```
-
\ No newline at end of file
+
+
+## Drafting Support
+
+Parallel flows come with [drafting support](20-drafting.mdx).
+
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftParallelExample.scala start=start_draft end=end_draft
+```
+
+
\ No newline at end of file
diff --git a/website/docs/operations/10-checkpoints.mdx b/website/docs/operations/10-checkpoints.mdx
index 6bc1b4e2..1a14c6e9 100644
--- a/website/docs/operations/10-checkpoints.mdx
+++ b/website/docs/operations/10-checkpoints.mdx
@@ -49,4 +49,18 @@ In practice, checkpointing and recovery are often used together to enable workfl
1. Version 1 of a workflow includes a segment that is checkpointed
2. Version 2 of the workflow removes that segment but includes a recovery mechanism
-3. When a workflow instance created with version 1 is resumed using version 2, the recovery mechanism processes the checkpoint event, allowing the workflow to continue without the removed segment
\ No newline at end of file
+3. When a workflow instance created with version 1 is resumed using version 2, the recovery mechanism processes the checkpoint event, allowing the workflow to continue without the removed segment
+
+## Drafting Support
+
+Checkpointing and recovery come with [drafting support](20-drafting.mdx).
+
+### Draft Checkpoint
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftCheckpointExample.scala start=start_draft_checkpoint end=end_draft_checkpoint
+```
+
+
+### Draft Checkpoint
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftCheckpointExample.scala start=start_draft_recovery end=end_draft_recovery
+```
+
diff --git a/website/docs/operations/11-retry.mdx b/website/docs/operations/11-retry.mdx
index 9c4c3b19..877385bd 100644
--- a/website/docs/operations/11-retry.mdx
+++ b/website/docs/operations/11-retry.mdx
@@ -57,4 +57,12 @@ If you see it as a major limitation, please reach out.
Use workflow-level retries for retry schedules spanning **minutes to hours or days**
-For short-lived retries (e.g., retrying within milliseconds or seconds), prefer handling them directly inside the `IO` operation using libraries like [`cats-retry`](https://github.com/cats-effect/cats-retry).
\ No newline at end of file
+For short-lived retries (e.g., retrying within milliseconds or seconds), prefer handling them directly inside the `IO` operation using libraries like [`cats-retry`](https://github.com/cats-effect/cats-retry).
+
+## Drafting Support
+
+Retries come with [drafting support](20-drafting.mdx).
+
+```scala file=./main/scala/workflows4s/example/docs/draft/DraftRetryExample.scala start=start_draft end=end_draft
+```
+
diff --git a/website/docs/operations/20-drafting.mdx b/website/docs/operations/20-drafting.mdx
new file mode 100644
index 00000000..865955dd
--- /dev/null
+++ b/website/docs/operations/20-drafting.mdx
@@ -0,0 +1,20 @@
+# Drafting
+
+Workflows4s comes with a dedicated API for creating renderable but NOT runnable workflow definitions.
+Its goal is to allow defining the structure of a workflow that can be discussed with the team or stakeholders,
+before committing more time to the actual implementation.
+
+The entire drafting API is exposed under `WIO.draft` and documented alongside specific operations.
+
+## Details
+
+Drafts use exactly the same model under the hood as real definitions, but filled with dummy logic.
+
+The drafting support simplifies the API in the following ways:
+
+* Not requiring type parameters
+* Not requiring event handling
+* Not requiring run logic
+* Automatically generating names from the context if not provided explicitly
+* Making as many parameters as possible optional
+
diff --git a/workflows4s-core/src/main/scala/workflows4s/wio/builders/DraftBuilder.scala b/workflows4s-core/src/main/scala/workflows4s/wio/builders/DraftBuilder.scala
index 44fa31b5..3aaa9304 100644
--- a/workflows4s-core/src/main/scala/workflows4s/wio/builders/DraftBuilder.scala
+++ b/workflows4s-core/src/main/scala/workflows4s/wio/builders/DraftBuilder.scala
@@ -13,19 +13,20 @@ object DraftBuilder {
trait Step0[Ctx <: WorkflowContext]() {
- def draft: DraftBuilderStep1 = DraftBuilderStep1()
+ val draft: DraftBuilderStep1.type = DraftBuilderStep1
- class DraftBuilderStep1 {
- def signal(name: String = null, error: String = null)(using autoName: sourcecode.Name): WIO.Draft[Ctx] = WIO.HandleSignal(
- draftSignal,
- SignalHandler[Unit, Unit, Any]((_, _) => ???),
- dummyEventHandler,
- WIO.HandleSignal.Meta(
- Option(error).map(ErrorMeta.Present(_)).getOrElse(ErrorMeta.noError),
- getEffectiveName(name, autoName),
- None,
- ),
- )
+ object DraftBuilderStep1 {
+ def signal(name: String = null, error: String = null)(using autoName: sourcecode.Name): WIO.Draft[Ctx] =
+ WIO.HandleSignal(
+ draftSignal,
+ SignalHandler[Unit, Unit, Any]((_, _) => ???),
+ dummyEventHandler,
+ WIO.HandleSignal.Meta(
+ Option(error).map(ErrorMeta.Present(_)).getOrElse(ErrorMeta.noError),
+ getEffectiveName(name, autoName),
+ None,
+ ),
+ )
def timer(name: String = null, duration: FiniteDuration = null)(using autoName: sourcecode.Name): WIO.Timer[Ctx, Any, Nothing, Nothing] =
WIO.Timer(
Option(duration) match {
@@ -47,6 +48,13 @@ object DraftBuilder {
),
)
+ def choice(name: String = null)(branches: (String, WIO.Draft[Ctx])*)(using autoName: sourcecode.Name): WIO.Draft[Ctx] = {
+ val branchWios = branches.map { case (branchName, wio) =>
+ WIO.Branch(_ => None, wio, Some(branchName))
+ }
+ WIO.Fork(branchWios.toVector, getEffectiveName(name, autoName).some, None)
+ }
+
def forEach(forEach: WIO.Draft[Ctx], name: String = null)(using autoName: sourcecode.Name): WIO.Draft[Ctx] = {
val effName = getEffectiveName(name, autoName).some
WIO.ForEach(_ => ???, forEach, () => ???, null, _ => ???, (_, _, _) => ???, (_, _) => ???, None, null, WIOMeta.ForEach(effName))
@@ -63,6 +71,80 @@ object DraftBuilder {
base.transformInput((_: Any) => ???).map(_ => ???)
}
+ def parallel(elements: WIO.Draft[Ctx]*): WIO.Draft[Ctx] = {
+ val parallelElements = elements.map { element =>
+ WIO.Parallel.Element(element.map(_ => ???), (interimState: WCState[Ctx], _: WCState[Ctx]) => interimState)
+ }
+ WIO
+ .Parallel[Ctx, Any, Nothing, WCState[Ctx], WCState[Ctx]](
+ elements = parallelElements,
+ formResult = _ => ???,
+ initialInterimState = (_: Any) => ???,
+ )
+ .transformInput((_: Any) => ???)
+ .map(_ => ???)
+ }
+
+ def recovery: WIO.Draft[Ctx] = WIO.Recovery(dummyEventHandler)
+
+ def interruptionSignal(
+ signalName: String = null,
+ operationName: String = null,
+ error: String = null,
+ )(using autoName: sourcecode.Name): WIO.Interruption[Ctx, Nothing, Nothing] = {
+ val draftSignalHandling = WIO
+ .HandleSignal(
+ draftSignal,
+ SignalHandler[Unit, Unit, WCState[Ctx]]((_, _) => ???),
+ dummyEventHandler[WCEvent[Ctx], Unit],
+ WIO.HandleSignal.Meta(
+ Option(error).map(ErrorMeta.Present(_)).getOrElse(ErrorMeta.noError),
+ Option(signalName).getOrElse(getEffectiveName(null, autoName)),
+ Option(operationName),
+ ),
+ )
+ .transformInput((_: WCState[Ctx]) => ???)
+ .map(_ => ???)
+ WIO.Interruption(draftSignalHandling, WIO.HandleInterruption.InterruptionType.Signal)
+ }
+
+ def interruptionTimeout(
+ timerName: String = null,
+ duration: FiniteDuration = null,
+ )(using autoName: sourcecode.Name): WIO.Interruption[Ctx, Nothing, Nothing] = {
+ val draftTimer = WIO
+ .Timer(
+ Option(duration) match {
+ case Some(value) => WIO.Timer.DurationSource.Static(value.toJava)
+ case None => WIO.Timer.DurationSource.Dynamic(_ => ???)
+ },
+ dummyEventHandler[WCEvent[Ctx], WIO.Timer.Started],
+ Option(timerName).orElse(getEffectiveName(null, autoName).some),
+ dummyEventHandler[WCEvent[Ctx], WIO.Timer.Released],
+ )
+ .transformInput((_: WCState[Ctx]) => ???)
+ .map(_ => ???)
+ WIO.Interruption(draftTimer, WIO.HandleInterruption.InterruptionType.Timer)
+ }
+
+ def retry(base: WIO.Draft[Ctx]): WIO.Draft[Ctx] = {
+ WIO
+ .Retry(
+ base,
+ (_: Throwable, _: WCState[Ctx], _: java.time.Instant) => ???,
+ )
+ .transformInput((_: Any) => ???)
+ .map(_ => ???)
+ }
+ def checkpoint(base: WIO.Draft[Ctx]): WIO.Draft[Ctx] = WIO.Checkpoint(base, (_, _) => ???, dummyEventHandler)
+
+ object syntax {
+ extension (base: WIO.Draft[Ctx]) {
+ def draftCheckpointed: WIO.Draft[Ctx] = checkpoint(base)
+ def draftRetry: WIO.Draft[Ctx] = retry(base)
+ }
+ }
+
}
}
diff --git a/workflows4s-core/src/test/scala/workflows4s/wio/WIODraftTest.scala b/workflows4s-core/src/test/scala/workflows4s/wio/WIODraftTest.scala
index a2660379..4cba4814 100644
--- a/workflows4s-core/src/test/scala/workflows4s/wio/WIODraftTest.scala
+++ b/workflows4s-core/src/test/scala/workflows4s/wio/WIODraftTest.scala
@@ -88,5 +88,42 @@ class WIODraftTest extends AnyFreeSpec with Matchers with OptionValues with Eith
case _ => fail("Expected Sequence model")
}
}
+
+ "should create a fork with correct branches" in {
+ val approve = WIO.draft.step("Approve")
+ val reject = WIO.draft.step("Reject")
+ val wio = WIO.draft.choice("Review")(
+ "Approved" -> approve,
+ "Rejected" -> reject,
+ )
+ val model = wio.toProgress.toModel
+
+ model match {
+ case WIOModel.Fork(branches, meta) =>
+ meta.name shouldBe Some("Review")
+ branches.length shouldBe 2
+
+ branches.head shouldBe WIOModel.RunIO(WIOMeta.RunIO(Some("Approve"), None, None))
+ branches(1) shouldBe WIOModel.RunIO(WIOMeta.RunIO(Some("Reject"), None, None))
+ case _ => fail("Expected Fork model")
+ }
+ }
+
+ "should create a parallel step with multiple elements" in {
+ val step1: Draft[Ctx] = WIO.draft.step("task1")
+ val step2: Draft[Ctx] = WIO.draft.step("task2")
+ val step3: Draft[Ctx] = WIO.draft.step("task3")
+ val parallel: Draft[Ctx] = WIO.draft.parallel(step1, step2, step3)
+ val model = parallel.toProgress.toModel
+
+ model match {
+ case WIOModel.Parallel(elements) =>
+ elements.length shouldBe 3
+ elements(0) shouldBe WIOModel.RunIO(WIOMeta.RunIO(Some("task1"), None, None))
+ elements(1) shouldBe WIOModel.RunIO(WIOMeta.RunIO(Some("task2"), None, None))
+ elements(2) shouldBe WIOModel.RunIO(WIOMeta.RunIO(Some("task3"), None, None))
+ case _ => fail("Expected Parallel model")
+ }
+ }
}
}
diff --git a/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftCheckpointExample.scala b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftCheckpointExample.scala
new file mode 100644
index 00000000..ae546766
--- /dev/null
+++ b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftCheckpointExample.scala
@@ -0,0 +1,20 @@
+package workflows4s.example.docs.draft
+
+import workflows4s.wio.DraftWorkflowContext.*
+
+object DraftCheckpointExample {
+
+ // start_draft_checkpoint
+ val base = WIO.draft.step()
+
+ val checkpointed = WIO.draft.checkpoint(base)
+
+ // or with a postfix application
+ import WIO.draft.syntax.*
+ val checkpointed2 = base.draftCheckpointed
+ // end_draft_checkpoint
+
+ // start_draft_recovery
+ val recovery = WIO.draft.recovery
+ // end_draft_recovery
+}
diff --git a/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftForkExample.scala b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftForkExample.scala
new file mode 100644
index 00000000..f9cbac56
--- /dev/null
+++ b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftForkExample.scala
@@ -0,0 +1,17 @@
+package workflows4s.example.docs.draft
+
+object DraftForkExample {
+
+ import workflows4s.wio.DraftWorkflowContext.*
+
+ // start_draft
+ val approveStep = WIO.draft.step("Approve")
+ val rejectStep = WIO.draft.step("Reject")
+
+ val approvalWorkflow = WIO.draft.choice("Review Decision")(
+ "Approved" -> approveStep,
+ "Rejected" -> rejectStep,
+ )
+ // end_draft
+
+}
diff --git a/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftInterruptionExample.scala b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftInterruptionExample.scala
new file mode 100644
index 00000000..fcd46bb9
--- /dev/null
+++ b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftInterruptionExample.scala
@@ -0,0 +1,23 @@
+package workflows4s.example.docs.draft
+
+import scala.concurrent.duration.*
+
+object DraftInterruptionExample {
+
+ import workflows4s.wio.DraftWorkflowContext.*
+
+ // start_draft
+ // Create signal and timeout interruptions
+ val urgentProcessing = WIO.draft.interruptionSignal("Urgent Processing Request")
+ val processingTimeout = WIO.draft.interruptionTimeout("Processing Deadline", 2.hours)
+
+ // Document processing workflow that can be interrupted
+ val documentProcessingWorkflow =
+ WIO.draft.step("Validate Document") >>>
+ WIO.draft
+ .step("Extract Content")
+ .interruptWith(urgentProcessing) // Can be interrupted for urgent processing
+ .interruptWith(processingTimeout) // Must complete within 2 hours
+ // end_draft
+
+}
diff --git a/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftLoopExample.scala b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftLoopExample.scala
new file mode 100644
index 00000000..fd35152d
--- /dev/null
+++ b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftLoopExample.scala
@@ -0,0 +1,23 @@
+package workflows4s.example.docs.draft
+
+import scala.concurrent.duration.*
+
+object DraftLoopExample {
+
+ import workflows4s.wio.DraftWorkflowContext.*
+
+ // start_draft
+ // Create a draft loop with a timer to avoid busy loops
+ val processStep = WIO.draft.step("Process Item")
+ val waitStep = WIO.draft.timer("Wait before retry", duration = 1.minute)
+
+ val loop = WIO.draft.repeat(
+ conditionName = "Is processing complete?",
+ releaseBranchName = "Yes",
+ restartBranchName = "No",
+ )(
+ body = processStep >>> waitStep,
+ onRestart = WIO.draft.step("Reset for retry"),
+ )
+ // end_draft
+}
diff --git a/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftParallelExample.scala b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftParallelExample.scala
new file mode 100644
index 00000000..eaa4ae2d
--- /dev/null
+++ b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftParallelExample.scala
@@ -0,0 +1,14 @@
+package workflows4s.example.docs.draft
+
+object DraftParallelExample {
+ import workflows4s.wio.DraftWorkflowContext.*
+
+ // start_draft
+ // Create a simple parallel workflow
+ val stepA = WIO.draft.step("Task A")
+ val stepB = WIO.draft.step("Task B")
+ val stepC = WIO.draft.step("Task C")
+
+ val parallelWorkflow = WIO.draft.parallel(stepA, stepB, stepC)
+ // end_draft
+}
diff --git a/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftRetryExample.scala b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftRetryExample.scala
new file mode 100644
index 00000000..795015c1
--- /dev/null
+++ b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftRetryExample.scala
@@ -0,0 +1,17 @@
+package workflows4s.example.docs.draft
+
+object DraftRetryExample {
+
+ import workflows4s.wio.DraftWorkflowContext.*
+
+ // start_draft
+ val apiCall = WIO.draft.step()
+
+ val withRetry = WIO.draft.retry(apiCall)
+
+ // or with a postfix application
+ import WIO.draft.syntax.*
+ val withRetry2 = apiCall.draftRetry
+ // end_draft
+
+}
diff --git a/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftSignalExample.scala b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftSignalExample.scala
new file mode 100644
index 00000000..4de8b2e0
--- /dev/null
+++ b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftSignalExample.scala
@@ -0,0 +1,11 @@
+package workflows4s.example.docs.draft
+
+object DraftSignalExample {
+
+ import workflows4s.wio.DraftWorkflowContext.*
+
+ // start_draft
+ val awaitApproval = WIO.draft.signal("Approval Required", error = "Rejected")
+ // end_draft
+
+}
diff --git a/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftStepExample.scala b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftStepExample.scala
new file mode 100644
index 00000000..d1c92e85
--- /dev/null
+++ b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftStepExample.scala
@@ -0,0 +1,12 @@
+package workflows4s.example.docs.draft
+
+import workflows4s.wio.DraftWorkflowContext.*
+
+object DraftStepExample {
+
+ // start_doc
+ val basic = WIO.draft.step()
+
+ val withError = WIO.draft.step(error = "MyError")
+ // end_doc
+}
diff --git a/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftTimerExample.scala b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftTimerExample.scala
new file mode 100644
index 00000000..8d37bf92
--- /dev/null
+++ b/workflows4s-example/src/main/scala/workflows4s/example/docs/draft/DraftTimerExample.scala
@@ -0,0 +1,14 @@
+package workflows4s.example.docs.draft
+
+import scala.concurrent.duration.*
+
+object DraftTimerExample {
+
+ import workflows4s.wio.DraftWorkflowContext.*
+
+ // start_draft
+ // Create timer operation with draft API
+ val waitForReview = WIO.draft.timer(duration = 24.hours)
+ // end_draft
+
+}
diff --git a/workflows4s-example/src/test/resources/docs/and-then.svg b/workflows4s-example/src/test/resources/docs/and-then.svg
index dae3e306..6f41522d 100644
--- a/workflows4s-example/src/test/resources/docs/and-then.svg
+++ b/workflows4s-example/src/test/resources/docs/and-then.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/checkpoint.svg b/workflows4s-example/src/test/resources/docs/checkpoint.svg
index 9f45b80f..ea42daf7 100644
--- a/workflows4s-example/src/test/resources/docs/checkpoint.svg
+++ b/workflows4s-example/src/test/resources/docs/checkpoint.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-checkpoint.bpmn b/workflows4s-example/src/test/resources/docs/draft-checkpoint.bpmn
new file mode 100644
index 00000000..97c0c746
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-checkpoint.bpmn
@@ -0,0 +1,38 @@
+
+
+
+
+ sequenceFlow_2
+
+
+ sequenceFlow_2
+ sequenceFlow_3
+
+
+
+ sequenceFlow_3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows4s-example/src/test/resources/docs/draft-checkpoint.json b/workflows4s-example/src/test/resources/docs/draft-checkpoint.json
new file mode 100644
index 00000000..ef3452ee
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-checkpoint.json
@@ -0,0 +1,11 @@
+{
+ "base" : {
+ "meta" : {
+ "name" : "Base",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ },
+ "_type" : "Checkpoint"
+}
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-checkpoint.mermaid b/workflows4s-example/src/test/resources/docs/draft-checkpoint.mermaid
new file mode 100644
index 00000000..b9280b3c
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-checkpoint.mermaid
@@ -0,0 +1,7 @@
+flowchart TD
+node0@{ shape: circle, label: "Start"}
+node1:::checkpoint
+subgraph node1 ["Checkpoint"]
+node2["Base"]
+node0 --> node2
+end
diff --git a/workflows4s-example/src/test/resources/docs/draft-checkpoint.svg b/workflows4s-example/src/test/resources/docs/draft-checkpoint.svg
new file mode 100644
index 00000000..2253c6b7
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-checkpoint.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-choice.bpmn b/workflows4s-example/src/test/resources/docs/draft-choice.bpmn
new file mode 100644
index 00000000..f9149c52
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-choice.bpmn
@@ -0,0 +1,86 @@
+
+
+
+
+ sequenceFlow_5
+
+
+ sequenceFlow_5
+ sequenceFlow_6
+ sequenceFlow_8
+
+
+
+
+
+
+ sequenceFlow_6
+ sequenceFlow_7
+
+
+ sequenceFlow_7
+ sequenceFlow_9
+ sequenceFlow_10
+
+
+
+
+
+
+ sequenceFlow_8
+ sequenceFlow_9
+
+
+
+ sequenceFlow_10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows4s-example/src/test/resources/docs/draft-choice.json b/workflows4s-example/src/test/resources/docs/draft-choice.json
new file mode 100644
index 00000000..0f78e027
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-choice.json
@@ -0,0 +1,32 @@
+{
+ "branches" : [
+ {
+ "meta" : {
+ "name" : "Approve",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ },
+ {
+ "meta" : {
+ "name" : "Reject",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ }
+ ],
+ "meta" : {
+ "name" : "Review Decision",
+ "branches" : [
+ {
+ "name" : "Approved"
+ },
+ {
+ "name" : "Rejected"
+ }
+ ]
+ },
+ "_type" : "Fork"
+}
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-choice.mermaid b/workflows4s-example/src/test/resources/docs/draft-choice.mermaid
new file mode 100644
index 00000000..cd59e09e
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-choice.mermaid
@@ -0,0 +1,8 @@
+flowchart TD
+node0@{ shape: circle, label: "Start"}
+node1@{ shape: hex, label: "Review Decision"}
+node0 --> node1
+node2["Approve"]
+node1 -->|"Approved"| node2
+node3["Reject"]
+node1 -->|"Rejected"| node3
diff --git a/workflows4s-example/src/test/resources/docs/draft-choice.svg b/workflows4s-example/src/test/resources/docs/draft-choice.svg
new file mode 100644
index 00000000..441d0ad7
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-choice.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-interruption.bpmn b/workflows4s-example/src/test/resources/docs/draft-interruption.bpmn
new file mode 100644
index 00000000..f40eea09
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-interruption.bpmn
@@ -0,0 +1,137 @@
+
+
+
+
+ sequenceFlow_9
+
+
+ sequenceFlow_9
+ sequenceFlow_15
+
+
+
+ sequenceFlow_15
+
+ sequenceFlow_12
+
+
+ sequenceFlow_12
+
+ sequenceFlow_10
+
+
+ sequenceFlow_10
+ sequenceFlow_11
+
+
+
+ sequenceFlow_11
+
+
+
+
+
+ sequenceFlow_13
+
+
+
+ sequenceFlow_13
+ sequenceFlow_14
+
+
+
+ sequenceFlow_14
+
+
+
+
+
+ sequenceFlow_16
+
+
+
+
+
+ sequenceFlow_16
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows4s-example/src/test/resources/docs/draft-interruption.json b/workflows4s-example/src/test/resources/docs/draft-interruption.json
new file mode 100644
index 00000000..1aefa461
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-interruption.json
@@ -0,0 +1,45 @@
+{
+ "steps" : [
+ {
+ "meta" : {
+ "name" : "Validate Document",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ },
+ {
+ "base" : {
+ "base" : {
+ "meta" : {
+ "name" : "Extract Content",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ },
+ "trigger" : {
+ "meta" : {
+ "signalName" : "Urgent Processing Request",
+ "operationName" : null,
+ "error" : null
+ },
+ "_type" : "HandleSignal"
+ },
+ "handler" : null,
+ "_type" : "Interruptible"
+ },
+ "trigger" : {
+ "meta" : {
+ "duration" : "PT2H",
+ "releaseAt" : null,
+ "name" : "Processing Deadline"
+ },
+ "_type" : "Timer"
+ },
+ "handler" : null,
+ "_type" : "Interruptible"
+ }
+ ],
+ "_type" : "Sequence"
+}
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-interruption.mermaid b/workflows4s-example/src/test/resources/docs/draft-interruption.mermaid
new file mode 100644
index 00000000..b3b8c1da
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-interruption.mermaid
@@ -0,0 +1,16 @@
+flowchart TD
+node0@{ shape: circle, label: "Start"}
+node1["Validate Document"]
+node0 --> node1
+subgraph node2 [" "]
+subgraph node3 [" "]
+node4["Extract Content"]
+node1 --> node4
+end
+node9@{ shape: stadium, label: "fa:fa-envelope Urgent Processing Request"}
+node3 --> node9
+node10["Handle Urgent Processing Request"]
+node9 --> node10
+end
+node14@{ shape: stadium, label: "fa:fa-clock Processing Deadline (2h)"}
+node2 --> node14
diff --git a/workflows4s-example/src/test/resources/docs/draft-interruption.svg b/workflows4s-example/src/test/resources/docs/draft-interruption.svg
new file mode 100644
index 00000000..de1088a3
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-interruption.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-loop.bpmn b/workflows4s-example/src/test/resources/docs/draft-loop.bpmn
new file mode 100644
index 00000000..37890b5b
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-loop.bpmn
@@ -0,0 +1,113 @@
+
+
+
+
+ sequenceFlow_8
+
+
+ sequenceFlow_8
+ sequenceFlow_14
+ sequenceFlow_9
+
+
+
+ sequenceFlow_9
+ sequenceFlow_10
+
+
+
+ sequenceFlow_10
+ sequenceFlow_11
+
+ 1m
+
+
+
+
+ sequenceFlow_11
+ sequenceFlow_12
+ sequenceFlow_13
+
+
+
+
+
+
+ sequenceFlow_12
+ sequenceFlow_15
+
+
+
+
+
+ sequenceFlow_13
+ sequenceFlow_14
+
+
+
+ sequenceFlow_15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows4s-example/src/test/resources/docs/draft-loop.json b/workflows4s-example/src/test/resources/docs/draft-loop.json
new file mode 100644
index 00000000..df5a0fee
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-loop.json
@@ -0,0 +1,37 @@
+{
+ "base" : {
+ "steps" : [
+ {
+ "meta" : {
+ "name" : "Process Item",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ },
+ {
+ "meta" : {
+ "duration" : "PT1M",
+ "releaseAt" : null,
+ "name" : "Wait before retry"
+ },
+ "_type" : "Timer"
+ }
+ ],
+ "_type" : "Sequence"
+ },
+ "onRestart" : {
+ "meta" : {
+ "name" : "Reset for retry",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ },
+ "meta" : {
+ "conditionName" : "Is processing complete?",
+ "exitBranchName" : "Yes",
+ "restartBranchName" : "No"
+ },
+ "_type" : "Loop"
+}
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-loop.mermaid b/workflows4s-example/src/test/resources/docs/draft-loop.mermaid
new file mode 100644
index 00000000..f7649d18
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-loop.mermaid
@@ -0,0 +1,12 @@
+flowchart TD
+node0:::executed@{ shape: circle, label: "Start"}
+node1["Process Item"]
+node0 --> node1
+node2@{ shape: stadium, label: "fa:fa-clock Wait before retry (1m)"}
+node1 --> node2
+node3@{ shape: hex, label: "Is processing complete?"}
+node2 --> node3
+node4["Reset for retry"]
+node3 -->|"No"| node4
+node4 --> node1
+classDef executed fill:#0e0
diff --git a/workflows4s-example/src/test/resources/docs/draft-loop.svg b/workflows4s-example/src/test/resources/docs/draft-loop.svg
new file mode 100644
index 00000000..59e20e1d
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-loop.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-parallel.bpmn b/workflows4s-example/src/test/resources/docs/draft-parallel.bpmn
new file mode 100644
index 00000000..c3c2b382
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-parallel.bpmn
@@ -0,0 +1,102 @@
+
+
+
+
+ sequenceFlow_4
+
+
+ sequenceFlow_4
+ sequenceFlow_5
+ sequenceFlow_7
+ sequenceFlow_9
+
+
+
+ sequenceFlow_5
+ sequenceFlow_6
+
+
+
+ sequenceFlow_6
+ sequenceFlow_8
+ sequenceFlow_10
+ sequenceFlow_11
+
+
+
+ sequenceFlow_7
+ sequenceFlow_8
+
+
+
+
+ sequenceFlow_9
+ sequenceFlow_10
+
+
+
+
+ sequenceFlow_11
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows4s-example/src/test/resources/docs/draft-parallel.json b/workflows4s-example/src/test/resources/docs/draft-parallel.json
new file mode 100644
index 00000000..81208edc
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-parallel.json
@@ -0,0 +1,29 @@
+{
+ "elements" : [
+ {
+ "meta" : {
+ "name" : "Task A",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ },
+ {
+ "meta" : {
+ "name" : "Task B",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ },
+ {
+ "meta" : {
+ "name" : "Task C",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ }
+ ],
+ "_type" : "Parallel"
+}
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-parallel.mermaid b/workflows4s-example/src/test/resources/docs/draft-parallel.mermaid
new file mode 100644
index 00000000..ca52d9a0
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-parallel.mermaid
@@ -0,0 +1,14 @@
+flowchart TD
+node0@{ shape: circle, label: "Start"}
+node1@{ shape: fork, label: ""}
+node0 --> node1
+node2["Task A"]
+node1 --> node2
+node3["Task B"]
+node1 --> node3
+node4["Task C"]
+node1 --> node4
+node5@{ shape: fork, label: ""}
+node2 --> node5
+node3 --> node5
+node4 --> node5
diff --git a/workflows4s-example/src/test/resources/docs/draft-parallel.svg b/workflows4s-example/src/test/resources/docs/draft-parallel.svg
new file mode 100644
index 00000000..44383a68
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-parallel.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-recovery.bpmn b/workflows4s-example/src/test/resources/docs/draft-recovery.bpmn
new file mode 100644
index 00000000..32b7bea5
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-recovery.bpmn
@@ -0,0 +1,26 @@
+
+
+
+
+ sequenceFlow_1
+
+
+ sequenceFlow_1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows4s-example/src/test/resources/docs/draft-recovery.json b/workflows4s-example/src/test/resources/docs/draft-recovery.json
new file mode 100644
index 00000000..2aaf490d
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-recovery.json
@@ -0,0 +1,3 @@
+{
+ "_type" : "Recovery"
+}
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-recovery.mermaid b/workflows4s-example/src/test/resources/docs/draft-recovery.mermaid
new file mode 100644
index 00000000..7037df50
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-recovery.mermaid
@@ -0,0 +1,4 @@
+flowchart TD
+node0@{ shape: circle, label: "Start"}
+node1@{ shape: hexagon, label: "fa:fa-wrench State Recovery"}
+node0 --> node1
diff --git a/workflows4s-example/src/test/resources/docs/draft-recovery.svg b/workflows4s-example/src/test/resources/docs/draft-recovery.svg
new file mode 100644
index 00000000..39520225
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-recovery.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-retry.bpmn b/workflows4s-example/src/test/resources/docs/draft-retry.bpmn
new file mode 100644
index 00000000..32b7bea5
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-retry.bpmn
@@ -0,0 +1,26 @@
+
+
+
+
+ sequenceFlow_1
+
+
+ sequenceFlow_1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows4s-example/src/test/resources/docs/draft-retry.json b/workflows4s-example/src/test/resources/docs/draft-retry.json
new file mode 100644
index 00000000..e87d2c95
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-retry.json
@@ -0,0 +1,11 @@
+{
+ "base" : {
+ "meta" : {
+ "name" : "Api Call",
+ "error" : null,
+ "description" : null
+ },
+ "_type" : "RunIO"
+ },
+ "_type" : "Retried"
+}
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-retry.mermaid b/workflows4s-example/src/test/resources/docs/draft-retry.mermaid
new file mode 100644
index 00000000..2c01566b
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-retry.mermaid
@@ -0,0 +1,4 @@
+flowchart TD
+node0@{ shape: circle, label: "Start"}
+node1["fa:fa-redo Api Call"]
+node0 --> node1
diff --git a/workflows4s-example/src/test/resources/docs/draft-retry.svg b/workflows4s-example/src/test/resources/docs/draft-retry.svg
new file mode 100644
index 00000000..43259b4b
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-retry.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-signal.bpmn b/workflows4s-example/src/test/resources/docs/draft-signal.bpmn
new file mode 100644
index 00000000..c653151e
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-signal.bpmn
@@ -0,0 +1,58 @@
+
+
+
+
+ sequenceFlow_5
+
+
+ sequenceFlow_5
+ sequenceFlow_6
+
+
+
+
+ sequenceFlow_6
+ sequenceFlow_7
+
+
+
+
+
+
+ sequenceFlow_7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows4s-example/src/test/resources/docs/draft-signal.json b/workflows4s-example/src/test/resources/docs/draft-signal.json
new file mode 100644
index 00000000..21d44c66
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-signal.json
@@ -0,0 +1,10 @@
+{
+ "meta" : {
+ "signalName" : "Approval Required",
+ "operationName" : null,
+ "error" : {
+ "name" : "Rejected"
+ }
+ },
+ "_type" : "HandleSignal"
+}
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-signal.mermaid b/workflows4s-example/src/test/resources/docs/draft-signal.mermaid
new file mode 100644
index 00000000..479d1b65
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-signal.mermaid
@@ -0,0 +1,6 @@
+flowchart TD
+node0@{ shape: circle, label: "Start"}
+node1@{ shape: stadium, label: "fa:fa-envelope Approval Required"}
+node0 --> node1
+node2["Handle Approval Required"]
+node1 --> node2
diff --git a/workflows4s-example/src/test/resources/docs/draft-signal.svg b/workflows4s-example/src/test/resources/docs/draft-signal.svg
new file mode 100644
index 00000000..5bada152
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-signal.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-timer.bpmn b/workflows4s-example/src/test/resources/docs/draft-timer.bpmn
new file mode 100644
index 00000000..c87e13f1
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-timer.bpmn
@@ -0,0 +1,41 @@
+
+
+
+
+ sequenceFlow_3
+
+
+ sequenceFlow_3
+ sequenceFlow_4
+
+ 24h
+
+
+
+
+ sequenceFlow_4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows4s-example/src/test/resources/docs/draft-timer.json b/workflows4s-example/src/test/resources/docs/draft-timer.json
new file mode 100644
index 00000000..462bf3c7
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-timer.json
@@ -0,0 +1,8 @@
+{
+ "meta" : {
+ "duration" : "PT24H",
+ "releaseAt" : null,
+ "name" : "Wait For Review"
+ },
+ "_type" : "Timer"
+}
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/draft-timer.mermaid b/workflows4s-example/src/test/resources/docs/draft-timer.mermaid
new file mode 100644
index 00000000..6390148e
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-timer.mermaid
@@ -0,0 +1,4 @@
+flowchart TD
+node0@{ shape: circle, label: "Start"}
+node1@{ shape: stadium, label: "fa:fa-clock Wait For Review (24h)"}
+node0 --> node1
diff --git a/workflows4s-example/src/test/resources/docs/draft-timer.svg b/workflows4s-example/src/test/resources/docs/draft-timer.svg
new file mode 100644
index 00000000..a7da734f
--- /dev/null
+++ b/workflows4s-example/src/test/resources/docs/draft-timer.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/flat-map.svg b/workflows4s-example/src/test/resources/docs/flat-map.svg
index 8478c55e..fc5b8733 100644
--- a/workflows4s-example/src/test/resources/docs/flat-map.svg
+++ b/workflows4s-example/src/test/resources/docs/flat-map.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/for-each-draft.svg b/workflows4s-example/src/test/resources/docs/for-each-draft.svg
index 87a24ec8..ef92cd39 100644
--- a/workflows4s-example/src/test/resources/docs/for-each-draft.svg
+++ b/workflows4s-example/src/test/resources/docs/for-each-draft.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/for-each.svg b/workflows4s-example/src/test/resources/docs/for-each.svg
index 3efac08e..abe1e3a3 100644
--- a/workflows4s-example/src/test/resources/docs/for-each.svg
+++ b/workflows4s-example/src/test/resources/docs/for-each.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/fork.svg b/workflows4s-example/src/test/resources/docs/fork.svg
index 9e64f1a7..280348d3 100644
--- a/workflows4s-example/src/test/resources/docs/fork.svg
+++ b/workflows4s-example/src/test/resources/docs/fork.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/handle-error-with.svg b/workflows4s-example/src/test/resources/docs/handle-error-with.svg
index 258b1569..80b97c31 100644
--- a/workflows4s-example/src/test/resources/docs/handle-error-with.svg
+++ b/workflows4s-example/src/test/resources/docs/handle-error-with.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/handle-signal.svg b/workflows4s-example/src/test/resources/docs/handle-signal.svg
index a7f84d70..7d39bd21 100644
--- a/workflows4s-example/src/test/resources/docs/handle-signal.svg
+++ b/workflows4s-example/src/test/resources/docs/handle-signal.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/interruption-signal.svg b/workflows4s-example/src/test/resources/docs/interruption-signal.svg
index b48c2a39..9b0b36dc 100644
--- a/workflows4s-example/src/test/resources/docs/interruption-signal.svg
+++ b/workflows4s-example/src/test/resources/docs/interruption-signal.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/loop.svg b/workflows4s-example/src/test/resources/docs/loop.svg
index f150c5b3..185b3606 100644
--- a/workflows4s-example/src/test/resources/docs/loop.svg
+++ b/workflows4s-example/src/test/resources/docs/loop.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/parallel.svg b/workflows4s-example/src/test/resources/docs/parallel.svg
index 2697439d..0f667de7 100644
--- a/workflows4s-example/src/test/resources/docs/parallel.svg
+++ b/workflows4s-example/src/test/resources/docs/parallel.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/pull-request-draft.svg b/workflows4s-example/src/test/resources/docs/pull-request-draft.svg
index 4c40421f..a451ac13 100644
--- a/workflows4s-example/src/test/resources/docs/pull-request-draft.svg
+++ b/workflows4s-example/src/test/resources/docs/pull-request-draft.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/pull-request.svg b/workflows4s-example/src/test/resources/docs/pull-request.svg
index 8018b8b0..a80217f5 100644
--- a/workflows4s-example/src/test/resources/docs/pull-request.svg
+++ b/workflows4s-example/src/test/resources/docs/pull-request.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/pure-error.svg b/workflows4s-example/src/test/resources/docs/pure-error.svg
index 14c268af..989181bf 100644
--- a/workflows4s-example/src/test/resources/docs/pure-error.svg
+++ b/workflows4s-example/src/test/resources/docs/pure-error.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/pure.svg b/workflows4s-example/src/test/resources/docs/pure.svg
index 0e3c986e..17c1ce91 100644
--- a/workflows4s-example/src/test/resources/docs/pure.svg
+++ b/workflows4s-example/src/test/resources/docs/pure.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/recovery.svg b/workflows4s-example/src/test/resources/docs/recovery.svg
index 0df9515a..79e67bac 100644
--- a/workflows4s-example/src/test/resources/docs/recovery.svg
+++ b/workflows4s-example/src/test/resources/docs/recovery.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/retry.svg b/workflows4s-example/src/test/resources/docs/retry.svg
index 2cfe7824..56988c43 100644
--- a/workflows4s-example/src/test/resources/docs/retry.svg
+++ b/workflows4s-example/src/test/resources/docs/retry.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/run-io-description.svg b/workflows4s-example/src/test/resources/docs/run-io-description.svg
index c4369f71..dc7931a2 100644
--- a/workflows4s-example/src/test/resources/docs/run-io-description.svg
+++ b/workflows4s-example/src/test/resources/docs/run-io-description.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/run-io-error.svg b/workflows4s-example/src/test/resources/docs/run-io-error.svg
index 7287d2e2..c661e4af 100644
--- a/workflows4s-example/src/test/resources/docs/run-io-error.svg
+++ b/workflows4s-example/src/test/resources/docs/run-io-error.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/run-io.svg b/workflows4s-example/src/test/resources/docs/run-io.svg
index 52192557..a37f60d2 100644
--- a/workflows4s-example/src/test/resources/docs/run-io.svg
+++ b/workflows4s-example/src/test/resources/docs/run-io.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/simple-loop.svg b/workflows4s-example/src/test/resources/docs/simple-loop.svg
index 4df6d1aa..439e4eb6 100644
--- a/workflows4s-example/src/test/resources/docs/simple-loop.svg
+++ b/workflows4s-example/src/test/resources/docs/simple-loop.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/resources/docs/timer.svg b/workflows4s-example/src/test/resources/docs/timer.svg
index b418947e..a3275bb0 100644
--- a/workflows4s-example/src/test/resources/docs/timer.svg
+++ b/workflows4s-example/src/test/resources/docs/timer.svg
@@ -1,4 +1,4 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/workflows4s-example/src/test/scala/workflows4s/example/docs/ExamplesTest.scala b/workflows4s-example/src/test/scala/workflows4s/example/docs/ExamplesTest.scala
index 33260ef1..a991afbe 100644
--- a/workflows4s-example/src/test/scala/workflows4s/example/docs/ExamplesTest.scala
+++ b/workflows4s-example/src/test/scala/workflows4s/example/docs/ExamplesTest.scala
@@ -2,6 +2,16 @@ package workflows4s.example.docs
import org.scalatest.freespec.AnyFreeSpec
import workflows4s.example.TestUtils
+import workflows4s.example.docs.draft.{
+ DraftCheckpointExample,
+ DraftForkExample,
+ DraftInterruptionExample,
+ DraftLoopExample,
+ DraftParallelExample,
+ DraftRetryExample,
+ DraftSignalExample,
+ DraftTimerExample,
+}
import workflows4s.example.docs.pullrequest.{PullRequestWorkflow, PullRequestWorkflowDraft}
import workflows4s.wio.WIO
@@ -14,17 +24,25 @@ class ExamplesTest extends AnyFreeSpec {
ExampleConfig("run-io-error", RunIOExample.doThingsWithError),
ExampleConfig("run-io-description", RunIOExample.doThingsWithDescription),
ExampleConfig("timer", TimerExample.waitForInput),
+ ExampleConfig("draft-timer", DraftTimerExample.waitForReview),
ExampleConfig("handle-signal", HandleSignalExample.doThings),
+ ExampleConfig("draft-signal", DraftSignalExample.awaitApproval),
ExampleConfig("and-then", SequencingExample.sequence1),
ExampleConfig("flat-map", SequencingExample.Dynamic.sequence1),
ExampleConfig("handle-error-with", HandleErrorExample.errorHandled),
ExampleConfig("simple-loop", LoopExample.Simple.loop),
ExampleConfig("loop", LoopExample.loop),
+ ExampleConfig("draft-loop", DraftLoopExample.loop),
ExampleConfig("fork", ForkExample.fork),
+ ExampleConfig("draft-choice", DraftForkExample.approvalWorkflow),
ExampleConfig("parallel", ParallelExample.parallel),
+ ExampleConfig("draft-parallel", DraftParallelExample.parallelWorkflow),
ExampleConfig("interruption-signal", InterruptionExample.interruptedThroughSignal),
+ ExampleConfig("draft-interruption", DraftInterruptionExample.documentProcessingWorkflow),
ExampleConfig("checkpoint", CheckpointExample.checkpoint.checkpointed, technical = true),
ExampleConfig("recovery", CheckpointExample.recovery.myWorkflow, technical = true),
+ ExampleConfig("draft-checkpoint", DraftCheckpointExample.checkpointed, technical = true),
+ ExampleConfig("draft-recovery", DraftCheckpointExample.recovery, technical = true),
ExampleConfig("pure", PureExample.doThings),
ExampleConfig("pure-error", PureExample.doThingsWithError),
ExampleConfig("pull-request-draft", PullRequestWorkflowDraft.workflow),
@@ -32,6 +50,7 @@ class ExamplesTest extends AnyFreeSpec {
ExampleConfig("for-each-draft", ForEachExample.draft.forEachDraft),
ExampleConfig("for-each", ForEachExample.real.forEachStep),
ExampleConfig("retry", RetryExample.withRetry),
+ ExampleConfig("draft-retry", DraftRetryExample.withRetry),
)
"examples" - {
@@ -49,7 +68,6 @@ class ExamplesTest extends AnyFreeSpec {
"render progress" in {
val instance = PullRequestWorkflow.run
TestUtils.renderDocsProgressExample(instance, "pull-request-completed")
-
}
}