From 3de3b64f14706d0e0411415aa1081ba43a6a580c Mon Sep 17 00:00:00 2001
From: HCaupert <hcaupert@takima.fr>
Date: Mon, 19 May 2025 16:47:12 +0200
Subject: [PATCH 1/2] solutions: added part 4/5 updated 2/3

---
 .../bakery/kitchen/KitchenWorkflowImpl.java   | 18 ++--
 .../bakery/MakeCookiesApp.java                | 10 --
 .../bakery/OrderCookiesApp.java               |  7 +-
 .../temporalpractice/bakery/bake/BakeApp.java | 12 +++
 .../{kitchen => }/bake/BakeService.java       |  6 +-
 .../{kitchen => }/bake/BakeServiceImpl.java   |  6 +-
 .../bakery/bake/dtos/BakeRequest.java         | 12 +++
 .../{kitchen => }/bake/dtos/BakeResult.java   |  4 +-
 .../bakery/batter/BatterApp.java              | 12 +++
 .../{kitchen => }/batter/BatterService.java   |  6 +-
 .../bakery/batter/BatterServiceImpl.java      | 21 +++++
 .../bakery/batter/dtos/Batter.java            | 10 ++
 .../batter/dtos/BatterCreationRequest.java    | 11 +++
 .../batter/dtos/BatterCreationResult.java     |  5 +
 .../bakery/kitchen/KitchenApp.java            | 13 +++
 .../bakery/kitchen/KitchenWorker.java         | 25 -----
 .../bakery/kitchen/KitchenWorkflow.java       | 14 ++-
 .../bakery/kitchen/KitchenWorkflowImpl.java   | 37 ++++++--
 .../bakery/kitchen/bake/dtos/BakeRequest.java | 12 ---
 .../kitchen/batter/BatterServiceImpl.java     | 21 -----
 .../bakery/kitchen/batter/dtos/Batter.java    | 10 --
 .../batter/dtos/BatterCreationRequest.java    | 11 ---
 .../batter/dtos/BatterCreationResult.java     |  5 -
 .../bakery/kitchen/dtos/KitchenDtos.java      | 91 ++++++++++---------
 .../bakery/temporal/TemporalQueues.java       |  6 +-
 .../bakery/temporal/TemporalUtils.java        |  2 -
 .../bakery/OrderCookiesApp.java               | 25 +++++
 .../bakery/OrderManyCookies.java              | 70 ++++++++++++++
 .../temporalpractice/bakery/bake/BakeApp.java | 12 +++
 .../bakery/bake/BakeService.java              | 12 +++
 .../bakery/bake/BakeServiceImpl.java          | 22 +++++
 .../bakery/bake/dtos/BakeRequest.java         | 12 +++
 .../bakery/bake/dtos/BakeResult.java          |  8 ++
 .../bakery/batter/BatterApp.java              | 12 +++
 .../bakery/batter/BatterService.java          | 13 +++
 .../bakery/batter/BatterServiceImpl.java      | 21 +++++
 .../bakery/batter/dtos/Batter.java            | 10 ++
 .../batter/dtos/BatterCreationRequest.java    | 11 +++
 .../batter/dtos/BatterCreationResult.java     |  5 +
 .../bakery/kitchen/KitchenApp.java            | 13 +++
 .../bakery/kitchen/KitchenWorkflow.java       | 21 +++++
 .../bakery/kitchen/KitchenWorkflowImpl.java   | 57 ++++++++++++
 .../bakery/kitchen/dtos/KitchenDtos.java      | 62 +++++++++++++
 .../bakery/temporal/TemporalQueues.java       |  7 ++
 .../bakery/temporal/TemporalUtils.java        | 51 +++++++++++
 .../bakery/CookieWorkflowTest.java            | 36 ++++++++
 46 files changed, 688 insertions(+), 179 deletions(-)
 delete mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/MakeCookiesApp.java
 create mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeApp.java
 rename solutions/day1/part-3.0/temporalpractice/bakery/{kitchen => }/bake/BakeService.java (50%)
 rename solutions/day1/part-3.0/temporalpractice/bakery/{kitchen => }/bake/BakeServiceImpl.java (76%)
 create mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/bake/dtos/BakeRequest.java
 rename solutions/day1/part-3.0/temporalpractice/bakery/{kitchen => }/bake/dtos/BakeResult.java (65%)
 create mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterApp.java
 rename solutions/day1/part-3.0/temporalpractice/bakery/{kitchen => }/batter/BatterService.java (51%)
 create mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterServiceImpl.java
 create mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/Batter.java
 create mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java
 create mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/BatterCreationResult.java
 create mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenApp.java
 delete mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorker.java
 delete mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/dtos/BakeRequest.java
 delete mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/BatterServiceImpl.java
 delete mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/Batter.java
 delete mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/BatterCreationRequest.java
 delete mode 100644 solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/BatterCreationResult.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/OrderCookiesApp.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/OrderManyCookies.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeApp.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeService.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeServiceImpl.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/bake/dtos/BakeRequest.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/bake/dtos/BakeResult.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterApp.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterService.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterServiceImpl.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/Batter.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/BatterCreationResult.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenApp.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenWorkflow.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/temporal/TemporalQueues.java
 create mode 100644 solutions/day1/part-4.1-start/temporalpractice/bakery/temporal/TemporalUtils.java
 create mode 100644 solutions/day1/part-5.1-start/temporalpractice/bakery/CookieWorkflowTest.java

diff --git a/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java b/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
index 529793a..8573360 100644
--- a/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
+++ b/solutions/day1/part-2/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
@@ -8,19 +8,13 @@ import io.temporal.workflow.Workflow;
 import java.time.Duration;
 
 public class KitchenWorkflowImpl implements KitchenWorkflow {
-    private final BatterService batterService;
-    private final BakeService bakeService;
-
-  public KitchenWorkflowImpl() {
-      ActivityOptions options = ActivityOptions.newBuilder()
-        .setTaskQueue("TheOneAndOnlyQueue")
-        .setStartToCloseTimeout(Duration.ofSeconds(10))
-        .build();
-
-      this.batterService = Workflow.newActivityStub(BatterService.class, options);
-      this.bakeService = Workflow.newActivityStub(BakeService.class, options);
-  }
 
+    private final ActivityOptions options = ActivityOptions.newBuilder()
+            .setTaskQueue("TheOneAndOnlyQueue")
+            .setStartToCloseTimeout(Duration.ofSeconds(10))
+            .build();
+    private final BatterService batterService = Workflow.newActivityStub(BatterService.class, options);
+    private final BakeService bakeService = Workflow.newActivityStub(BakeService.class, options);
 
   @Override
     public void makeCookies() {
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/MakeCookiesApp.java b/solutions/day1/part-3.0/temporalpractice/bakery/MakeCookiesApp.java
deleted file mode 100644
index 2ea7f9b..0000000
--- a/solutions/day1/part-3.0/temporalpractice/bakery/MakeCookiesApp.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package io.takima.temporalpractice.bakery;
-
-import io.takima.temporalpractice.bakery.kitchen.KitchenWorker;
-
-public class MakeCookiesApp {
-    public static void main(String[] args) {
-        // This app should execute the making of all cookies ordered
-        new KitchenWorker().start();
-    }
-}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/OrderCookiesApp.java b/solutions/day1/part-3.0/temporalpractice/bakery/OrderCookiesApp.java
index 4dd036c..2ff2b24 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/OrderCookiesApp.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/OrderCookiesApp.java
@@ -12,10 +12,13 @@ public class OrderCookiesApp {
     public static void main(String[] args) {
         // This app simulates an order of cookies
         // It should call the workflow which makes cookies
-
         var orderRequest = CookieOrderRequest.random();
 
-        KitchenWorkflow workflow = TemporalUtils.newWorkflowStub(KitchenWorkflow.class, TemporalQueues.KITCHEN, "kitchen-" + orderRequest.orderId());
+        KitchenWorkflow workflow = TemporalUtils.newWorkflowStub(
+                KitchenWorkflow.class,
+                TemporalQueues.KITCHEN,
+                "kitchen-" + orderRequest.orderId()
+        );
 
         workflow.makeCookies(orderRequest); // Start the Workflow Execution
     }
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeApp.java b/solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeApp.java
new file mode 100644
index 0000000..2d1cdb1
--- /dev/null
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeApp.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+
+public class BakeApp {
+    public static void main(String[] args) {
+        var worker = TemporalUtils.newWorker(TemporalQueues.BAKE);
+        worker.registerActivitiesImplementations(new BakeServiceImpl());
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/BakeService.java b/solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeService.java
similarity index 50%
rename from solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/BakeService.java
rename to solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeService.java
index a0e42de..36c0d02 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/BakeService.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeService.java
@@ -1,7 +1,7 @@
-package io.takima.temporalpractice.bakery.kitchen.bake;
+package io.takima.temporalpractice.bakery.bake;
 
-import io.takima.temporalpractice.bakery.kitchen.bake.dtos.BakeRequest;
-import io.takima.temporalpractice.bakery.kitchen.bake.dtos.BakeResult;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
 import io.temporal.activity.ActivityInterface;
 import io.temporal.activity.ActivityMethod;
 
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/BakeServiceImpl.java b/solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeServiceImpl.java
similarity index 76%
rename from solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/BakeServiceImpl.java
rename to solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeServiceImpl.java
index 4924604..22509b6 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/BakeServiceImpl.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/bake/BakeServiceImpl.java
@@ -1,7 +1,7 @@
-package io.takima.temporalpractice.bakery.kitchen.bake;
+package io.takima.temporalpractice.bakery.bake;
 
-import io.takima.temporalpractice.bakery.kitchen.bake.dtos.BakeRequest;
-import io.takima.temporalpractice.bakery.kitchen.bake.dtos.BakeResult;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
 import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Cookie;
 
 import java.util.ArrayList;
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/bake/dtos/BakeRequest.java b/solutions/day1/part-3.0/temporalpractice/bakery/bake/dtos/BakeRequest.java
new file mode 100644
index 0000000..42701fe
--- /dev/null
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/bake/dtos/BakeRequest.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake.dtos;
+
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.BakingPreference;
+
+public record BakeRequest(
+        String orderId,
+        Batter batter,
+        BakingPreference bakingPreference
+) {
+}
+
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/dtos/BakeResult.java b/solutions/day1/part-3.0/temporalpractice/bakery/bake/dtos/BakeResult.java
similarity index 65%
rename from solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/dtos/BakeResult.java
rename to solutions/day1/part-3.0/temporalpractice/bakery/bake/dtos/BakeResult.java
index 3bdca8f..f9afcf7 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/dtos/BakeResult.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/bake/dtos/BakeResult.java
@@ -1,8 +1,8 @@
-package io.takima.temporalpractice.bakery.kitchen.bake.dtos;
+package io.takima.temporalpractice.bakery.bake.dtos;
 
 import java.util.List;
 
-import static io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.*;
+import static io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Cookie;
 
 public record BakeResult(List<Cookie> cookies) {
 }
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterApp.java b/solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterApp.java
new file mode 100644
index 0000000..8b4bdb9
--- /dev/null
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterApp.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+
+public class BatterApp {
+    public static void main(String[] args) {
+        var worker = TemporalUtils.newWorker(TemporalQueues.BATTER);
+        worker.registerActivitiesImplementations(new BatterServiceImpl());
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/BatterService.java b/solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterService.java
similarity index 51%
rename from solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/BatterService.java
rename to solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterService.java
index e9f7434..7da3e9f 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/BatterService.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterService.java
@@ -1,7 +1,7 @@
-package io.takima.temporalpractice.bakery.kitchen.batter;
+package io.takima.temporalpractice.bakery.batter;
 
-import io.takima.temporalpractice.bakery.kitchen.batter.dtos.BatterCreationRequest;
-import io.takima.temporalpractice.bakery.kitchen.batter.dtos.BatterCreationResult;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
 import io.temporal.activity.ActivityInterface;
 import io.temporal.activity.ActivityMethod;
 
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterServiceImpl.java b/solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterServiceImpl.java
new file mode 100644
index 0000000..b594d07
--- /dev/null
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/batter/BatterServiceImpl.java
@@ -0,0 +1,21 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+
+public class BatterServiceImpl implements BatterService {
+
+    static final int BATTER_QTY_PER_COOKIE_IN_GRAMS = 30; // in grams
+
+    @Override
+    public BatterCreationResult prepareBatter(BatterCreationRequest request) {
+        System.out.println("Mixing flour, sugar, and love for " + request.targetCookieCount() + " cookies with topping " + request.targetTopping());
+        return new BatterCreationResult(
+                new Batter(
+                        request.targetTopping(),
+                        BATTER_QTY_PER_COOKIE_IN_GRAMS * request.targetCookieCount(),
+                        request.targetCookieCount()
+                ));
+    }
+}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/Batter.java b/solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/Batter.java
new file mode 100644
index 0000000..8608c0e
--- /dev/null
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/Batter.java
@@ -0,0 +1,10 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
+
+public record Batter(
+        Topping topping,
+        int quantityInGrams,
+        int targetCookieCount
+) {
+}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java b/solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java
new file mode 100644
index 0000000..38cc0c1
--- /dev/null
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java
@@ -0,0 +1,11 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
+
+public record BatterCreationRequest(
+        String orderId,
+        Topping targetTopping,
+        int targetCookieCount
+) {
+
+}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/BatterCreationResult.java b/solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/BatterCreationResult.java
new file mode 100644
index 0000000..d75e6ab
--- /dev/null
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/batter/dtos/BatterCreationResult.java
@@ -0,0 +1,5 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+public record BatterCreationResult(Batter batter) {
+
+}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenApp.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenApp.java
new file mode 100644
index 0000000..4c57367
--- /dev/null
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenApp.java
@@ -0,0 +1,13 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.worker.Worker;
+
+public class KitchenApp {
+    public static void main(String[] args) {
+        Worker worker = TemporalUtils.newWorker(TemporalQueues.KITCHEN);
+        worker.registerWorkflowImplementationTypes(KitchenWorkflowImpl.class);
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorker.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorker.java
deleted file mode 100644
index fbc3ed7..0000000
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorker.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package io.takima.temporalpractice.bakery.kitchen;
-
-import io.takima.temporalpractice.bakery.kitchen.bake.BakeServiceImpl;
-import io.takima.temporalpractice.bakery.kitchen.batter.BatterServiceImpl;
-import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
-import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
-import io.temporal.client.WorkflowClient;
-import io.temporal.client.WorkflowOptions;
-import io.temporal.serviceclient.WorkflowServiceStubs;
-import io.temporal.worker.Worker;
-import io.temporal.worker.WorkerFactory;
-
-public class KitchenWorker {
-  public void start() {
-    Worker worker = TemporalUtils.newWorker(TemporalQueues.KITCHEN);
-
-    // Register workflows
-    worker.registerWorkflowImplementationTypes(KitchenWorkflowImpl.class);
-    // Register activities
-    worker.registerActivitiesImplementations(new BakeServiceImpl());
-    worker.registerActivitiesImplementations(new BatterServiceImpl());
-
-    TemporalUtils.startWorkerFactory();
-  }
-}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorkflow.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorkflow.java
index 9f7fb09..ca26635 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorkflow.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorkflow.java
@@ -1,13 +1,21 @@
 package io.takima.temporalpractice.bakery.kitchen;
 
-import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos;
 import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
 import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
+import io.temporal.workflow.QueryMethod;
+import io.temporal.workflow.SignalMethod;
 import io.temporal.workflow.WorkflowInterface;
 import io.temporal.workflow.WorkflowMethod;
 
 @WorkflowInterface
 public interface KitchenWorkflow {
-  @WorkflowMethod
-  CookieOrderResult makeCookies(CookieOrderRequest request);
+    @WorkflowMethod
+    CookieOrderResult makeCookies(CookieOrderRequest request);
+
+    @SignalMethod
+    void ovenReady();
+
+    @QueryMethod
+    CookieOrderStatus getStatus();
 }
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
index e4e5026..df0bedc 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
@@ -1,14 +1,14 @@
 package io.takima.temporalpractice.bakery.kitchen;
 
-import io.takima.temporalpractice.bakery.kitchen.bake.BakeService;
-import io.takima.temporalpractice.bakery.kitchen.bake.dtos.BakeRequest;
-import io.takima.temporalpractice.bakery.kitchen.batter.BatterService;
-import io.takima.temporalpractice.bakery.kitchen.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.bake.BakeService;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.batter.BatterService;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
 import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
 import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
 import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
 import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
-import io.temporal.activity.ActivityOptions;
 import io.temporal.workflow.Workflow;
 
 import java.time.Duration;
@@ -16,23 +16,42 @@ import java.time.Duration;
 public class KitchenWorkflowImpl implements KitchenWorkflow {
   private final BatterService batterService;
   private final BakeService bakeService;
+  private boolean ovenReady = false;
+  private CookieOrderRequest cookieOrder;
 
   public KitchenWorkflowImpl() {
-    this.batterService = TemporalUtils.newActivityStub(BatterService.class, TemporalQueues.KITCHEN);
-    this.bakeService = TemporalUtils.newActivityStub(BakeService.class, TemporalQueues.KITCHEN);
+    this.batterService = TemporalUtils.newActivityStub(BatterService.class, TemporalQueues.BATTER);
+    this.bakeService = TemporalUtils.newActivityStub(BakeService.class, TemporalQueues.BAKE);
   }
 
 
   @Override
   public CookieOrderResult makeCookies(CookieOrderRequest request) {
-    // Note: System.out.println is used here for simplicity
-    // In real applications, you should use proper Workflow-aware logging (we'll cover this in Day 2)
+    this.cookieOrder = request;
+    var timer = Workflow.newTimer(Duration.ofSeconds(30));
+
     System.out.println("Order " + request.orderId() + ": Starting to prepare " + request.quantity() + " cookies with topping " + request.topping() + " and baking preference " + request.bakingPreference());
+
     var batterCreationResult = batterService.prepareBatter(new BatterCreationRequest(request.orderId(), request.topping(), request.quantity()));
     var batter = batterCreationResult.batter();
+
+    Workflow.await(() -> ovenReady);
+
     var bakeResult = bakeService.bake(new BakeRequest(request.orderId(), batter, request.bakingPreference()));
 
     System.out.println("Order " + request.orderId() + ": Your " + bakeResult.cookies().size() + " cookies are ready!");
+
+    timer.get();
     return new CookieOrderResult(request.orderId(), bakeResult.cookies());
   }
+
+  @Override
+  public void ovenReady() {
+    this.ovenReady = true;
+  }
+
+  @Override
+  public CookieOrderStatus getStatus() {
+    return new CookieOrderStatus(ovenReady, cookieOrder);
+  }
 }
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/dtos/BakeRequest.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/dtos/BakeRequest.java
deleted file mode 100644
index ee64b42..0000000
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/bake/dtos/BakeRequest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.takima.temporalpractice.bakery.kitchen.bake.dtos;
-
-import io.takima.temporalpractice.bakery.kitchen.batter.dtos.Batter;
-import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.BakingPreference;
-
-public record BakeRequest(
-  String orderId,
-  Batter batter,
-  BakingPreference bakingPreference
-) {
-}
-
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/BatterServiceImpl.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/BatterServiceImpl.java
deleted file mode 100644
index 2e000fe..0000000
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/BatterServiceImpl.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package io.takima.temporalpractice.bakery.kitchen.batter;
-
-import io.takima.temporalpractice.bakery.kitchen.batter.dtos.Batter;
-import io.takima.temporalpractice.bakery.kitchen.batter.dtos.BatterCreationRequest;
-import io.takima.temporalpractice.bakery.kitchen.batter.dtos.BatterCreationResult;
-
-public class BatterServiceImpl implements BatterService {
-
-  static final int BATTER_QTY_PER_COOKIE_IN_GRAMS = 30; // in grams
-
-  @Override
-  public BatterCreationResult prepareBatter(BatterCreationRequest request) {
-    System.out.println("Mixing flour, sugar, and love for " + request.targetCookieCount() + " cookies with topping " + request.targetTopping());
-    return new BatterCreationResult(
-      new Batter(
-        request.targetTopping(),
-        BATTER_QTY_PER_COOKIE_IN_GRAMS * request.targetCookieCount(),
-        request.targetCookieCount()
-      ));
-  }
-}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/Batter.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/Batter.java
deleted file mode 100644
index 0a703c2..0000000
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/Batter.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package io.takima.temporalpractice.bakery.kitchen.batter.dtos;
-
-import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
-
-public record Batter(
-  Topping topping,
-  int quantityInGrams,
-  int targetCookieCount
-) {
-}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/BatterCreationRequest.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/BatterCreationRequest.java
deleted file mode 100644
index 43d419c..0000000
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/BatterCreationRequest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.takima.temporalpractice.bakery.kitchen.batter.dtos;
-
-import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
-
-public record BatterCreationRequest(
-  String orderId,
-  Topping targetTopping,
-  int targetCookieCount
-) {
-
-}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/BatterCreationResult.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/BatterCreationResult.java
deleted file mode 100644
index d350d80..0000000
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/batter/dtos/BatterCreationResult.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package io.takima.temporalpractice.bakery.kitchen.batter.dtos;
-
-public record BatterCreationResult(Batter batter) {
-
-}
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java
index 1e90f23..f82ef2e 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java
@@ -1,59 +1,62 @@
 package io.takima.temporalpractice.bakery.kitchen.dtos;
 
-import org.checkerframework.checker.units.qual.C;
-
 import java.util.List;
 import java.util.UUID;
 
 public interface KitchenDtos {
+    enum BakingPreference {
+        RAW,
+        SOFT,
+        COOKED,
+        BURNT;
+
+        public static BakingPreference random() {
+            return values()[(int) (Math.random() * values().length)];
+        }
+    }
 
-  enum BakingPreference {
-    RAW,
-    SOFT,
-    COOKED,
-    BURNT;
+    enum Topping {
+        CHOCOLATE,
+        NUTS,
+        NONE;
 
-    public static BakingPreference random() {
-      return values()[(int) (Math.random() * values().length)];
+        public static Topping random() {
+            return values()[(int) (Math.random() * values().length)];
+        }
     }
-  }
 
-  enum Topping {
-    CHOCOLATE,
-    NUTS,
-    NONE;
+    record Cookie(
+            BakingPreference bakingPreference,
+            Topping topping
+    ) {
+    }
 
-    public static Topping random() {
-      return values()[(int) (Math.random() * values().length)];
+    record CookieOrderRequest(
+            String orderId,
+            int quantity,
+            BakingPreference bakingPreference,
+            Topping topping
+    ) {
+
+        public static CookieOrderRequest random() {
+            return new CookieOrderRequest(
+                    UUID.randomUUID().toString(),
+                    (int) (Math.random() * 10) + 1,
+                    BakingPreference.random(),
+                    Topping.random()
+            );
+        }
     }
-  }
-
-  record Cookie(
-    BakingPreference bakingPreference,
-    Topping topping
-  ) {
-  }
-
-  record CookieOrderRequest(
-    String orderId,
-    int quantity,
-    BakingPreference bakingPreference,
-    Topping topping
-  ) {
-
-    public static CookieOrderRequest random() {
-      return new CookieOrderRequest(
-        UUID.randomUUID().toString(),
-        (int) (Math.random() * 10) + 1,
-        BakingPreference.random(),
-        Topping.random()
-      );
+
+    record CookieOrderResult(
+            String orderId,
+            List<Cookie> cookies
+    ) {
     }
-  }
 
-  record CookieOrderResult(
-    String orderId,
-    List<Cookie> cookies
-  ) {
-  }
+    record CookieOrderStatus(
+            boolean ovenReady,
+            CookieOrderRequest request
+    ) {
+    }
 }
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/temporal/TemporalQueues.java b/solutions/day1/part-3.0/temporalpractice/bakery/temporal/TemporalQueues.java
index 0d15137..0c99053 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/temporal/TemporalQueues.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/temporal/TemporalQueues.java
@@ -1,5 +1,7 @@
 package io.takima.temporalpractice.bakery.temporal;
 
-public abstract class TemporalQueues {
-  public static final String KITCHEN = "TheOneAndOnlyQueue";
+public class TemporalQueues {
+  public static final String KITCHEN = "kitchen";
+  public static final String BATTER = "batter";
+  public static final String BAKE = "bake";
 }
diff --git a/solutions/day1/part-3.0/temporalpractice/bakery/temporal/TemporalUtils.java b/solutions/day1/part-3.0/temporalpractice/bakery/temporal/TemporalUtils.java
index ea0bfa3..f004ff9 100644
--- a/solutions/day1/part-3.0/temporalpractice/bakery/temporal/TemporalUtils.java
+++ b/solutions/day1/part-3.0/temporalpractice/bakery/temporal/TemporalUtils.java
@@ -48,6 +48,4 @@ public class TemporalUtils {
         .build()
     );
   }
-
-
 }
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/OrderCookiesApp.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/OrderCookiesApp.java
new file mode 100644
index 0000000..2ff2b24
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/OrderCookiesApp.java
@@ -0,0 +1,25 @@
+package io.takima.temporalpractice.bakery;
+
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+
+public class OrderCookiesApp {
+    public static void main(String[] args) {
+        // This app simulates an order of cookies
+        // It should call the workflow which makes cookies
+        var orderRequest = CookieOrderRequest.random();
+
+        KitchenWorkflow workflow = TemporalUtils.newWorkflowStub(
+                KitchenWorkflow.class,
+                TemporalQueues.KITCHEN,
+                "kitchen-" + orderRequest.orderId()
+        );
+
+        workflow.makeCookies(orderRequest); // Start the Workflow Execution
+    }
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/OrderManyCookies.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/OrderManyCookies.java
new file mode 100644
index 0000000..6421088
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/OrderManyCookies.java
@@ -0,0 +1,70 @@
+package io.takima.temporalpractice.bakery;
+
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.api.enums.v1.ParentClosePolicy;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.workflow.*;
+import org.slf4j.Logger;
+
+import java.time.Duration;
+
+public class OrderManyCookies {
+    public static void main(String[] args) {
+        var queue = "manycookies";
+
+        TemporalUtils.newWorker(queue)
+                .registerWorkflowImplementationTypes(ManyCookiesImpl.class);
+
+        TemporalUtils.startWorkerFactory();
+
+        try {
+            ManyCookies manyCookies = TemporalUtils.CLIENT.newWorkflowStub(
+                    ManyCookies.class,
+                    WorkflowOptions.newBuilder().setWorkflowId("cookie-orderer").setTaskQueue(queue).build()
+            );
+            WorkflowClient.start(manyCookies::continuousOrders);
+        } catch (Exception e) {
+            System.out.println("Many cookies already running, skipping...");
+        }
+    }
+
+    public static class ManyCookiesImpl implements ManyCookies {
+
+        private static final Logger logger = Workflow.getLogger(ManyCookiesImpl.class);
+
+        @Override
+        public void continuousOrders() {
+
+            var options = ChildWorkflowOptions.newBuilder()
+                    .setWorkflowId("order-" + Workflow.randomUUID())
+                    .setTaskQueue(TemporalQueues.KITCHEN)
+                    .setParentClosePolicy(ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON)
+                    .build();
+            var kitchenWorkflow = Workflow.newChildWorkflowStub(KitchenWorkflow.class, options);
+
+            var quantity = Workflow.newRandom().nextInt(1, 5);
+            var baking = KitchenDtos.BakingPreference.values()[Workflow.newRandom().nextInt(KitchenDtos.BakingPreference.values().length)];
+            var topping = KitchenDtos.Topping.values()[Workflow.newRandom().nextInt(KitchenDtos.Topping.values().length)];
+
+            var cookiesPreferences = new KitchenDtos.CookieOrderRequest(Workflow.randomUUID().toString(), quantity, baking, topping);
+
+            logger.info("Ordering cookies\n{}", cookiesPreferences);
+            Async.function(kitchenWorkflow::makeCookies, cookiesPreferences);
+
+            Workflow.sleep(Duration.ofSeconds(10));
+            kitchenWorkflow.ovenReady();
+
+            Workflow.continueAsNew();
+        }
+    }
+
+    @WorkflowInterface
+    public interface ManyCookies {
+        @WorkflowMethod
+        void continuousOrders();
+    }
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeApp.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeApp.java
new file mode 100644
index 0000000..2d1cdb1
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeApp.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+
+public class BakeApp {
+    public static void main(String[] args) {
+        var worker = TemporalUtils.newWorker(TemporalQueues.BAKE);
+        worker.registerActivitiesImplementations(new BakeServiceImpl());
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeService.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeService.java
new file mode 100644
index 0000000..36c0d02
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeService.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityMethod;
+
+@ActivityInterface
+public interface BakeService {
+    @ActivityMethod
+    BakeResult bake(BakeRequest request);
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeServiceImpl.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeServiceImpl.java
new file mode 100644
index 0000000..22509b6
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/BakeServiceImpl.java
@@ -0,0 +1,22 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Cookie;
+
+import java.util.ArrayList;
+
+public class BakeServiceImpl implements BakeService {
+  @Override
+  public BakeResult bake(BakeRequest request) {
+    System.out.println("Will bake those cookies " + request.bakingPreference());
+    var cookies = new ArrayList<Cookie>();
+    for (int i = 0; i < request.batter().targetCookieCount(); i++) {
+      // Making cookies out of batter
+      var cookie = new Cookie(request.bakingPreference(), request.batter().topping());
+      // Add it to the cookies after it is baked
+      cookies.add(cookie);
+    }
+    return new BakeResult(cookies);
+  }
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/dtos/BakeRequest.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/dtos/BakeRequest.java
new file mode 100644
index 0000000..42701fe
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/dtos/BakeRequest.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake.dtos;
+
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.BakingPreference;
+
+public record BakeRequest(
+        String orderId,
+        Batter batter,
+        BakingPreference bakingPreference
+) {
+}
+
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/dtos/BakeResult.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/dtos/BakeResult.java
new file mode 100644
index 0000000..f9afcf7
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/bake/dtos/BakeResult.java
@@ -0,0 +1,8 @@
+package io.takima.temporalpractice.bakery.bake.dtos;
+
+import java.util.List;
+
+import static io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Cookie;
+
+public record BakeResult(List<Cookie> cookies) {
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterApp.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterApp.java
new file mode 100644
index 0000000..8b4bdb9
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterApp.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+
+public class BatterApp {
+    public static void main(String[] args) {
+        var worker = TemporalUtils.newWorker(TemporalQueues.BATTER);
+        worker.registerActivitiesImplementations(new BatterServiceImpl());
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterService.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterService.java
new file mode 100644
index 0000000..7da3e9f
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterService.java
@@ -0,0 +1,13 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityMethod;
+
+@ActivityInterface
+public interface BatterService {
+
+    @ActivityMethod
+    BatterCreationResult prepareBatter(BatterCreationRequest request);
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterServiceImpl.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterServiceImpl.java
new file mode 100644
index 0000000..b594d07
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/BatterServiceImpl.java
@@ -0,0 +1,21 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+
+public class BatterServiceImpl implements BatterService {
+
+    static final int BATTER_QTY_PER_COOKIE_IN_GRAMS = 30; // in grams
+
+    @Override
+    public BatterCreationResult prepareBatter(BatterCreationRequest request) {
+        System.out.println("Mixing flour, sugar, and love for " + request.targetCookieCount() + " cookies with topping " + request.targetTopping());
+        return new BatterCreationResult(
+                new Batter(
+                        request.targetTopping(),
+                        BATTER_QTY_PER_COOKIE_IN_GRAMS * request.targetCookieCount(),
+                        request.targetCookieCount()
+                ));
+    }
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/Batter.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/Batter.java
new file mode 100644
index 0000000..8608c0e
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/Batter.java
@@ -0,0 +1,10 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
+
+public record Batter(
+        Topping topping,
+        int quantityInGrams,
+        int targetCookieCount
+) {
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java
new file mode 100644
index 0000000..38cc0c1
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java
@@ -0,0 +1,11 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
+
+public record BatterCreationRequest(
+        String orderId,
+        Topping targetTopping,
+        int targetCookieCount
+) {
+
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/BatterCreationResult.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/BatterCreationResult.java
new file mode 100644
index 0000000..d75e6ab
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/batter/dtos/BatterCreationResult.java
@@ -0,0 +1,5 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+public record BatterCreationResult(Batter batter) {
+
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenApp.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenApp.java
new file mode 100644
index 0000000..4c57367
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenApp.java
@@ -0,0 +1,13 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.worker.Worker;
+
+public class KitchenApp {
+    public static void main(String[] args) {
+        Worker worker = TemporalUtils.newWorker(TemporalQueues.KITCHEN);
+        worker.registerWorkflowImplementationTypes(KitchenWorkflowImpl.class);
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenWorkflow.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenWorkflow.java
new file mode 100644
index 0000000..ca26635
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenWorkflow.java
@@ -0,0 +1,21 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
+import io.temporal.workflow.QueryMethod;
+import io.temporal.workflow.SignalMethod;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+
+@WorkflowInterface
+public interface KitchenWorkflow {
+    @WorkflowMethod
+    CookieOrderResult makeCookies(CookieOrderRequest request);
+
+    @SignalMethod
+    void ovenReady();
+
+    @QueryMethod
+    CookieOrderStatus getStatus();
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
new file mode 100644
index 0000000..df0bedc
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
@@ -0,0 +1,57 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.bake.BakeService;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.batter.BatterService;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.workflow.Workflow;
+
+import java.time.Duration;
+
+public class KitchenWorkflowImpl implements KitchenWorkflow {
+  private final BatterService batterService;
+  private final BakeService bakeService;
+  private boolean ovenReady = false;
+  private CookieOrderRequest cookieOrder;
+
+  public KitchenWorkflowImpl() {
+    this.batterService = TemporalUtils.newActivityStub(BatterService.class, TemporalQueues.BATTER);
+    this.bakeService = TemporalUtils.newActivityStub(BakeService.class, TemporalQueues.BAKE);
+  }
+
+
+  @Override
+  public CookieOrderResult makeCookies(CookieOrderRequest request) {
+    this.cookieOrder = request;
+    var timer = Workflow.newTimer(Duration.ofSeconds(30));
+
+    System.out.println("Order " + request.orderId() + ": Starting to prepare " + request.quantity() + " cookies with topping " + request.topping() + " and baking preference " + request.bakingPreference());
+
+    var batterCreationResult = batterService.prepareBatter(new BatterCreationRequest(request.orderId(), request.topping(), request.quantity()));
+    var batter = batterCreationResult.batter();
+
+    Workflow.await(() -> ovenReady);
+
+    var bakeResult = bakeService.bake(new BakeRequest(request.orderId(), batter, request.bakingPreference()));
+
+    System.out.println("Order " + request.orderId() + ": Your " + bakeResult.cookies().size() + " cookies are ready!");
+
+    timer.get();
+    return new CookieOrderResult(request.orderId(), bakeResult.cookies());
+  }
+
+  @Override
+  public void ovenReady() {
+    this.ovenReady = true;
+  }
+
+  @Override
+  public CookieOrderStatus getStatus() {
+    return new CookieOrderStatus(ovenReady, cookieOrder);
+  }
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java
new file mode 100644
index 0000000..f82ef2e
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java
@@ -0,0 +1,62 @@
+package io.takima.temporalpractice.bakery.kitchen.dtos;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface KitchenDtos {
+    enum BakingPreference {
+        RAW,
+        SOFT,
+        COOKED,
+        BURNT;
+
+        public static BakingPreference random() {
+            return values()[(int) (Math.random() * values().length)];
+        }
+    }
+
+    enum Topping {
+        CHOCOLATE,
+        NUTS,
+        NONE;
+
+        public static Topping random() {
+            return values()[(int) (Math.random() * values().length)];
+        }
+    }
+
+    record Cookie(
+            BakingPreference bakingPreference,
+            Topping topping
+    ) {
+    }
+
+    record CookieOrderRequest(
+            String orderId,
+            int quantity,
+            BakingPreference bakingPreference,
+            Topping topping
+    ) {
+
+        public static CookieOrderRequest random() {
+            return new CookieOrderRequest(
+                    UUID.randomUUID().toString(),
+                    (int) (Math.random() * 10) + 1,
+                    BakingPreference.random(),
+                    Topping.random()
+            );
+        }
+    }
+
+    record CookieOrderResult(
+            String orderId,
+            List<Cookie> cookies
+    ) {
+    }
+
+    record CookieOrderStatus(
+            boolean ovenReady,
+            CookieOrderRequest request
+    ) {
+    }
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/temporal/TemporalQueues.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/temporal/TemporalQueues.java
new file mode 100644
index 0000000..0c99053
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/temporal/TemporalQueues.java
@@ -0,0 +1,7 @@
+package io.takima.temporalpractice.bakery.temporal;
+
+public class TemporalQueues {
+  public static final String KITCHEN = "kitchen";
+  public static final String BATTER = "batter";
+  public static final String BAKE = "bake";
+}
diff --git a/solutions/day1/part-4.1-start/temporalpractice/bakery/temporal/TemporalUtils.java b/solutions/day1/part-4.1-start/temporalpractice/bakery/temporal/TemporalUtils.java
new file mode 100644
index 0000000..f004ff9
--- /dev/null
+++ b/solutions/day1/part-4.1-start/temporalpractice/bakery/temporal/TemporalUtils.java
@@ -0,0 +1,51 @@
+package io.takima.temporalpractice.bakery.temporal;
+
+
+import io.temporal.activity.ActivityOptions;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerFactory;
+import io.temporal.workflow.Workflow;
+
+import java.time.Duration;
+
+public class TemporalUtils {
+
+  // Represents the connection to your local cluster. For now, lets keep it simple
+  private static final WorkflowServiceStubs SERVICE_STUBS = WorkflowServiceStubs.newLocalServiceStubs();
+
+  // Your key for interacting with the Temporal world.
+  public static final WorkflowClient CLIENT = WorkflowClient.newInstance(SERVICE_STUBS);
+
+  private static final WorkerFactory FACTORY = WorkerFactory.newInstance(CLIENT);
+
+  public static Worker newWorker(String queue) {
+    return FACTORY.newWorker(queue);
+  }
+
+  public static void startWorkerFactory() {
+    FACTORY.start();
+  }
+
+  public static <T> T newWorkflowStub(Class<T> workflowInterface, String queue, String workflowId) {
+    return CLIENT.newWorkflowStub(
+      workflowInterface,
+      WorkflowOptions.newBuilder()
+        .setTaskQueue(queue)
+        .setWorkflowId(workflowId)
+        .build()
+    );
+  }
+
+  public static <T> T newActivityStub(Class<T> workflowInterface, String queue) {
+    return Workflow.newActivityStub(
+      workflowInterface,
+      ActivityOptions.newBuilder()
+        .setTaskQueue(queue)
+        .setStartToCloseTimeout(Duration.ofSeconds(5))
+        .build()
+    );
+  }
+}
diff --git a/solutions/day1/part-5.1-start/temporalpractice/bakery/CookieWorkflowTest.java b/solutions/day1/part-5.1-start/temporalpractice/bakery/CookieWorkflowTest.java
new file mode 100644
index 0000000..aa06ecb
--- /dev/null
+++ b/solutions/day1/part-5.1-start/temporalpractice/bakery/CookieWorkflowTest.java
@@ -0,0 +1,36 @@
+package io.takima.temporalpractice.bakery.cookie;
+
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import io.temporal.worker.Worker;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class CookieWorkflowTest {
+
+    @RegisterExtension
+    public static final TestWorkflowExtension testWorkflowExtension =
+            TestWorkflowExtension.newBuilder()
+                    //FIXME: register the KitchenWorkflowImpl
+                    //FIXME: add doNotStart()
+                    .build();
+
+    @BeforeEach
+    void init(TestWorkflowEnvironment testEnv){
+        //FIXME: create bake and batter workers
+    }
+
+    @Test
+    public void testWorkflowExecution(
+            // Test environment for configuration
+            TestWorkflowEnvironment testEnv,
+            // Worker for registering additional implementations
+            Worker worker,
+            // Auto-created Workflow stub
+            KitchenWorkflow workflow
+    ) {
+        //FIXME: Run your workflow and test it!
+    }
+}
-- 
GitLab


From 950c29164b753db97d41a2ce7b1361625dbbb981 Mon Sep 17 00:00:00 2001
From: HCaupert <hcaupert@takima.fr>
Date: Wed, 21 May 2025 11:02:10 +0200
Subject: [PATCH 2/2] solutions: more solutions

---
 .../bakery/CookieWorkflowTest.java            |  74 +++
 .../bakery/CookieWorkflowTest.java            | 100 ++++
 .../bakery/OrderCookiesApp.java               |  25 +
 .../bakery/OrderManyCookies.java              |  70 +++
 .../temporalpractice/bakery/bake/BakeApp.java |  12 +
 .../bakery/bake/BakeService.java              |  12 +
 .../bakery/bake/BakeServiceImpl.java          |  22 +
 .../bakery/bake/dtos/BakeRequest.java         |  12 +
 .../bakery/bake/dtos/BakeResult.java          |   8 +
 .../bakery/batter/BatterApp.java              |  12 +
 .../bakery/batter/BatterService.java          |  17 +
 .../bakery/batter/BatterServiceImpl.java      |  27 ++
 .../bakery/batter/dtos/Batter.java            |  10 +
 .../batter/dtos/BatterCleanupRequest.java     |   4 +
 .../batter/dtos/BatterCreationRequest.java    |  11 +
 .../batter/dtos/BatterCreationResult.java     |   5 +
 .../bakery/kitchen/KitchenApp.java            |  13 +
 .../bakery/kitchen/KitchenWorkflow.java       |  21 +
 .../bakery/kitchen/KitchenWorkflowImpl.java   |  72 +++
 .../bakery/kitchen/dtos/KitchenDtos.java      |  62 +++
 .../temporal/TemporalActivityFactory.java     |  20 +
 .../bakery/temporal/TemporalQueues.java       |   7 +
 .../bakery/temporal/TemporalUtils.java        |  36 ++
 .../part-1.3/main/resources/application.yml   |   3 +
 .../bakery/cookie/CookieWorkflowTest.java     | 122 +++++
 .../day2/part-2.1/bakery/OrderCookiesApp.java |  25 +
 .../part-2.1/bakery/OrderManyCookies.java     |  70 +++
 .../day2/part-2.1/bakery/bake/BakeApp.java    |  12 +
 .../part-2.1/bakery/bake/BakeService.java     |  12 +
 .../part-2.1/bakery/bake/BakeServiceImpl.java |  22 +
 .../bakery/bake/dtos/BakeRequest.java         |  12 +
 .../part-2.1/bakery/bake/dtos/BakeResult.java |   8 +
 .../part-2.1/bakery/batter/BatterApp.java     |  12 +
 .../part-2.1/bakery/batter/BatterService.java |  17 +
 .../bakery/batter/BatterServiceImpl.java      |  27 ++
 .../part-2.1/bakery/batter/dtos/Batter.java   |  10 +
 .../batter/dtos/BatterCleanupRequest.java     |   4 +
 .../batter/dtos/BatterCreationRequest.java    |  11 +
 .../batter/dtos/BatterCreationResult.java     |   5 +
 .../part-2.1/bakery/kitchen/KitchenApp.java   |  14 +
 .../bakery/kitchen/KitchenWorkflow.java       |  23 +
 .../bakery/kitchen/KitchenWorkflowImpl.java   |  72 +++
 .../kitchen/KitchenWorkflowImplLegacy.java    |  73 +++
 .../bakery/kitchen/KitchenWorkflowLegacy.java |  24 +
 .../bakery/kitchen/dtos/KitchenDtos.java      |  62 +++
 .../temporal/TemporalActivityFactory.java     |  20 +
 .../bakery/temporal/TemporalQueues.java       |   7 +
 .../bakery/temporal/TemporalUtils.java        |  36 ++
 .../java/io/takima/temporalpractice/.gitkeep  |   0
 .../bakery/cookie/CookieWorkflowTest.java     | 130 ++++++
 .../day2/part-2.2/test/resources/history.json | 437 ++++++++++++++++++
 51 files changed, 1922 insertions(+)
 create mode 100644 solutions/day1/part-5.1-end/temporalpractice/bakery/CookieWorkflowTest.java
 create mode 100644 solutions/day1/part-5.2-end/temporalpractice/bakery/CookieWorkflowTest.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/OrderCookiesApp.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/OrderManyCookies.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeApp.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeService.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeServiceImpl.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/dtos/BakeRequest.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/dtos/BakeResult.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterApp.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterService.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterServiceImpl.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/Batter.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCleanupRequest.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCreationResult.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenApp.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenWorkflow.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalActivityFactory.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalQueues.java
 create mode 100644 solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalUtils.java
 create mode 100644 solutions/day2/part-1.3/main/resources/application.yml
 create mode 100644 solutions/day2/part-1.3/test/java/io/takima/temporalpractice/bakery/cookie/CookieWorkflowTest.java
 create mode 100644 solutions/day2/part-2.1/bakery/OrderCookiesApp.java
 create mode 100644 solutions/day2/part-2.1/bakery/OrderManyCookies.java
 create mode 100644 solutions/day2/part-2.1/bakery/bake/BakeApp.java
 create mode 100644 solutions/day2/part-2.1/bakery/bake/BakeService.java
 create mode 100644 solutions/day2/part-2.1/bakery/bake/BakeServiceImpl.java
 create mode 100644 solutions/day2/part-2.1/bakery/bake/dtos/BakeRequest.java
 create mode 100644 solutions/day2/part-2.1/bakery/bake/dtos/BakeResult.java
 create mode 100644 solutions/day2/part-2.1/bakery/batter/BatterApp.java
 create mode 100644 solutions/day2/part-2.1/bakery/batter/BatterService.java
 create mode 100644 solutions/day2/part-2.1/bakery/batter/BatterServiceImpl.java
 create mode 100644 solutions/day2/part-2.1/bakery/batter/dtos/Batter.java
 create mode 100644 solutions/day2/part-2.1/bakery/batter/dtos/BatterCleanupRequest.java
 create mode 100644 solutions/day2/part-2.1/bakery/batter/dtos/BatterCreationRequest.java
 create mode 100644 solutions/day2/part-2.1/bakery/batter/dtos/BatterCreationResult.java
 create mode 100644 solutions/day2/part-2.1/bakery/kitchen/KitchenApp.java
 create mode 100644 solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflow.java
 create mode 100644 solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowImpl.java
 create mode 100644 solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowImplLegacy.java
 create mode 100644 solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowLegacy.java
 create mode 100644 solutions/day2/part-2.1/bakery/kitchen/dtos/KitchenDtos.java
 create mode 100644 solutions/day2/part-2.1/bakery/temporal/TemporalActivityFactory.java
 create mode 100644 solutions/day2/part-2.1/bakery/temporal/TemporalQueues.java
 create mode 100644 solutions/day2/part-2.1/bakery/temporal/TemporalUtils.java
 create mode 100644 solutions/day2/part-2.2/test/java/io/takima/temporalpractice/.gitkeep
 create mode 100644 solutions/day2/part-2.2/test/java/io/takima/temporalpractice/bakery/cookie/CookieWorkflowTest.java
 create mode 100644 solutions/day2/part-2.2/test/resources/history.json

diff --git a/solutions/day1/part-5.1-end/temporalpractice/bakery/CookieWorkflowTest.java b/solutions/day1/part-5.1-end/temporalpractice/bakery/CookieWorkflowTest.java
new file mode 100644
index 0000000..5de07e2
--- /dev/null
+++ b/solutions/day1/part-5.1-end/temporalpractice/bakery/CookieWorkflowTest.java
@@ -0,0 +1,74 @@
+package io.takima.temporalpractice.bakery.cookie;
+
+import io.takima.temporalpractice.bakery.bake.BakeServiceImpl;
+import io.takima.temporalpractice.bakery.batter.BatterServiceImpl;
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflowImpl;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.temporal.client.WorkflowClient;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import java.time.Duration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CookieWorkflowTest {
+
+    @RegisterExtension
+    public static final TestWorkflowExtension testWorkflowExtension =
+            TestWorkflowExtension.newBuilder()
+                    .registerWorkflowImplementationTypes(KitchenWorkflowImpl.class)
+                    .setDoNotStart(true)
+                    .build();
+
+    @BeforeEach
+    void init(TestWorkflowEnvironment testEnv){
+        testEnv.newWorker(TemporalQueues.BAKE)
+                .registerActivitiesImplementations(new BakeServiceImpl());
+        testEnv.newWorker(TemporalQueues.BATTER)
+                .registerActivitiesImplementations(new BatterServiceImpl());
+        testEnv.start();
+    }
+
+    @Test
+    public void shouldMakeCookies(
+            // Test environment for configuration
+            TestWorkflowEnvironment testEnv,
+            // Auto-created Workflow stub
+            KitchenWorkflow workflow
+    ) {
+        // get the env starting time
+        var startTime = testEnv.currentTimeMillis();
+
+        // Start the workflow asynchronously
+        var request = KitchenDtos.CookieOrderRequest.random();
+        WorkflowClient.start(workflow::makeCookies, request);
+
+        var status = workflow.getStatus();
+        assertThat(status.ovenReady()).isFalse();
+        assertThat(status.request()).isEqualTo(request);
+
+        workflow.ovenReady();
+        status = workflow.getStatus();
+        assertThat(status.ovenReady()).isTrue();
+
+        // Get the workflow result
+        var result = workflow.makeCookies(request);
+
+        assertThat(result.orderId()).isEqualTo(request.orderId());
+        assertThat(result.cookies())
+                .hasSize(request.quantity())
+                .allSatisfy(cookie -> {
+                    assertThat(cookie.bakingPreference()).isEqualTo(request.bakingPreference());
+                    assertThat(cookie.topping()).isEqualTo(request.topping());
+                });
+
+        var duration = Duration.ofMillis(testEnv.currentTimeMillis() - startTime);
+        assertThat(duration).isGreaterThan(Duration.ofSeconds(30));
+    }
+}
diff --git a/solutions/day1/part-5.2-end/temporalpractice/bakery/CookieWorkflowTest.java b/solutions/day1/part-5.2-end/temporalpractice/bakery/CookieWorkflowTest.java
new file mode 100644
index 0000000..9d37dd4
--- /dev/null
+++ b/solutions/day1/part-5.2-end/temporalpractice/bakery/CookieWorkflowTest.java
@@ -0,0 +1,100 @@
+package io.takima.temporalpractice.bakery.cookie;
+
+import io.takima.temporalpractice.bakery.bake.BakeService;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
+import io.takima.temporalpractice.bakery.batter.BatterService;
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflowImpl;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.temporal.client.WorkflowClient;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.time.Duration;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class CookieWorkflowTest {
+
+    @Mock(withoutAnnotations = true)
+    private BakeService bakeService;
+
+    @Mock(withoutAnnotations = true)
+    private BatterService batterService;
+
+
+    @RegisterExtension
+    public static final TestWorkflowExtension testWorkflowExtension =
+            TestWorkflowExtension.newBuilder()
+                    .registerWorkflowImplementationTypes(KitchenWorkflowImpl.class)
+                    .setDoNotStart(true)
+                    .build();
+
+    @BeforeEach
+    void init(TestWorkflowEnvironment testEnv) {
+        testEnv.newWorker(TemporalQueues.BAKE)
+                .registerActivitiesImplementations(bakeService);
+        testEnv.newWorker(TemporalQueues.BATTER)
+                .registerActivitiesImplementations(batterService);
+        testEnv.start();
+    }
+
+    KitchenDtos.CookieOrderRequest request = KitchenDtos.CookieOrderRequest.random();
+    BatterCreationRequest batterCreationRequest = new BatterCreationRequest(request.orderId(), request.topping(), request.quantity());
+    BatterCreationResult batterCreationResult = new BatterCreationResult(new Batter(request.topping(), 30 * request.quantity(), request.quantity()));
+    BakeRequest bakeRequest = new BakeRequest(request.orderId(), batterCreationResult.batter(), request.bakingPreference());
+    BakeResult bakeResult = new BakeResult(List.of(new KitchenDtos.Cookie(request.bakingPreference(), request.topping())));
+
+    @Test
+    public void shouldMakeCookies(
+            // Test environment for configuration
+            TestWorkflowEnvironment testEnv,
+            // Auto-created Workflow stub
+            KitchenWorkflow workflow
+    ) {
+        // get the env starting time
+        var startTime = testEnv.currentTimeMillis();
+
+        // Start the workflow asynchronously
+        WorkflowClient.start(workflow::makeCookies, request);
+        when(batterService.prepareBatter(batterCreationRequest))
+                .thenReturn(batterCreationResult);
+        // Make sure we dont bake before the oven is ready
+        verifyNoInteractions(bakeService);
+
+        var status = workflow.getStatus();
+        assertThat(status.ovenReady()).isFalse();
+        assertThat(status.request()).isEqualTo(request);
+
+        workflow.ovenReady();
+        status = workflow.getStatus();
+        assertThat(status.ovenReady()).isTrue();
+        when(bakeService.bake(bakeRequest)).thenReturn(bakeResult);
+
+        // Get the workflow result
+        var result = workflow.makeCookies(request);
+
+        assertThat(result.orderId()).isEqualTo(request.orderId());
+        assertThat(result.cookies())
+                .isEqualTo(bakeResult.cookies());
+
+        var duration = Duration.ofMillis(testEnv.currentTimeMillis() - startTime);
+        assertThat(duration).isGreaterThan(Duration.ofSeconds(30));
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/OrderCookiesApp.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/OrderCookiesApp.java
new file mode 100644
index 0000000..2ff2b24
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/OrderCookiesApp.java
@@ -0,0 +1,25 @@
+package io.takima.temporalpractice.bakery;
+
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+
+public class OrderCookiesApp {
+    public static void main(String[] args) {
+        // This app simulates an order of cookies
+        // It should call the workflow which makes cookies
+        var orderRequest = CookieOrderRequest.random();
+
+        KitchenWorkflow workflow = TemporalUtils.newWorkflowStub(
+                KitchenWorkflow.class,
+                TemporalQueues.KITCHEN,
+                "kitchen-" + orderRequest.orderId()
+        );
+
+        workflow.makeCookies(orderRequest); // Start the Workflow Execution
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/OrderManyCookies.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/OrderManyCookies.java
new file mode 100644
index 0000000..6421088
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/OrderManyCookies.java
@@ -0,0 +1,70 @@
+package io.takima.temporalpractice.bakery;
+
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.api.enums.v1.ParentClosePolicy;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.workflow.*;
+import org.slf4j.Logger;
+
+import java.time.Duration;
+
+public class OrderManyCookies {
+    public static void main(String[] args) {
+        var queue = "manycookies";
+
+        TemporalUtils.newWorker(queue)
+                .registerWorkflowImplementationTypes(ManyCookiesImpl.class);
+
+        TemporalUtils.startWorkerFactory();
+
+        try {
+            ManyCookies manyCookies = TemporalUtils.CLIENT.newWorkflowStub(
+                    ManyCookies.class,
+                    WorkflowOptions.newBuilder().setWorkflowId("cookie-orderer").setTaskQueue(queue).build()
+            );
+            WorkflowClient.start(manyCookies::continuousOrders);
+        } catch (Exception e) {
+            System.out.println("Many cookies already running, skipping...");
+        }
+    }
+
+    public static class ManyCookiesImpl implements ManyCookies {
+
+        private static final Logger logger = Workflow.getLogger(ManyCookiesImpl.class);
+
+        @Override
+        public void continuousOrders() {
+
+            var options = ChildWorkflowOptions.newBuilder()
+                    .setWorkflowId("order-" + Workflow.randomUUID())
+                    .setTaskQueue(TemporalQueues.KITCHEN)
+                    .setParentClosePolicy(ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON)
+                    .build();
+            var kitchenWorkflow = Workflow.newChildWorkflowStub(KitchenWorkflow.class, options);
+
+            var quantity = Workflow.newRandom().nextInt(1, 5);
+            var baking = KitchenDtos.BakingPreference.values()[Workflow.newRandom().nextInt(KitchenDtos.BakingPreference.values().length)];
+            var topping = KitchenDtos.Topping.values()[Workflow.newRandom().nextInt(KitchenDtos.Topping.values().length)];
+
+            var cookiesPreferences = new KitchenDtos.CookieOrderRequest(Workflow.randomUUID().toString(), quantity, baking, topping);
+
+            logger.info("Ordering cookies\n{}", cookiesPreferences);
+            Async.function(kitchenWorkflow::makeCookies, cookiesPreferences);
+
+            Workflow.sleep(Duration.ofSeconds(10));
+            kitchenWorkflow.ovenReady();
+
+            Workflow.continueAsNew();
+        }
+    }
+
+    @WorkflowInterface
+    public interface ManyCookies {
+        @WorkflowMethod
+        void continuousOrders();
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeApp.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeApp.java
new file mode 100644
index 0000000..2d1cdb1
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeApp.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+
+public class BakeApp {
+    public static void main(String[] args) {
+        var worker = TemporalUtils.newWorker(TemporalQueues.BAKE);
+        worker.registerActivitiesImplementations(new BakeServiceImpl());
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeService.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeService.java
new file mode 100644
index 0000000..36c0d02
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeService.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityMethod;
+
+@ActivityInterface
+public interface BakeService {
+    @ActivityMethod
+    BakeResult bake(BakeRequest request);
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeServiceImpl.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeServiceImpl.java
new file mode 100644
index 0000000..22509b6
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/BakeServiceImpl.java
@@ -0,0 +1,22 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Cookie;
+
+import java.util.ArrayList;
+
+public class BakeServiceImpl implements BakeService {
+  @Override
+  public BakeResult bake(BakeRequest request) {
+    System.out.println("Will bake those cookies " + request.bakingPreference());
+    var cookies = new ArrayList<Cookie>();
+    for (int i = 0; i < request.batter().targetCookieCount(); i++) {
+      // Making cookies out of batter
+      var cookie = new Cookie(request.bakingPreference(), request.batter().topping());
+      // Add it to the cookies after it is baked
+      cookies.add(cookie);
+    }
+    return new BakeResult(cookies);
+  }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/dtos/BakeRequest.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/dtos/BakeRequest.java
new file mode 100644
index 0000000..42701fe
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/dtos/BakeRequest.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake.dtos;
+
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.BakingPreference;
+
+public record BakeRequest(
+        String orderId,
+        Batter batter,
+        BakingPreference bakingPreference
+) {
+}
+
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/dtos/BakeResult.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/dtos/BakeResult.java
new file mode 100644
index 0000000..f9afcf7
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/bake/dtos/BakeResult.java
@@ -0,0 +1,8 @@
+package io.takima.temporalpractice.bakery.bake.dtos;
+
+import java.util.List;
+
+import static io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Cookie;
+
+public record BakeResult(List<Cookie> cookies) {
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterApp.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterApp.java
new file mode 100644
index 0000000..8b4bdb9
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterApp.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+
+public class BatterApp {
+    public static void main(String[] args) {
+        var worker = TemporalUtils.newWorker(TemporalQueues.BATTER);
+        worker.registerActivitiesImplementations(new BatterServiceImpl());
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterService.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterService.java
new file mode 100644
index 0000000..1353c54
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterService.java
@@ -0,0 +1,17 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCleanupRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityMethod;
+
+@ActivityInterface
+public interface BatterService {
+
+    @ActivityMethod
+    BatterCreationResult prepareBatter(BatterCreationRequest request);
+
+    @ActivityMethod
+    void cleanupBatterIfNeeded(BatterCleanupRequest request);
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterServiceImpl.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterServiceImpl.java
new file mode 100644
index 0000000..17a2e83
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/BatterServiceImpl.java
@@ -0,0 +1,27 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCleanupRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+
+public class BatterServiceImpl implements BatterService {
+
+    static final int BATTER_QTY_PER_COOKIE_IN_GRAMS = 30; // in grams
+
+    @Override
+    public BatterCreationResult prepareBatter(BatterCreationRequest request) {
+        System.out.println("Mixing flour, sugar, and love for " + request.targetCookieCount() + " cookies with topping " + request.targetTopping());
+        return new BatterCreationResult(
+                new Batter(
+                        request.targetTopping(),
+                        BATTER_QTY_PER_COOKIE_IN_GRAMS * request.targetCookieCount(),
+                        request.targetCookieCount()
+                ));
+    }
+
+    @Override
+    public void cleanupBatterIfNeeded(BatterCleanupRequest request) {
+        System.out.println("Cleaning up batter of order " + request.orderId());
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/Batter.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/Batter.java
new file mode 100644
index 0000000..8608c0e
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/Batter.java
@@ -0,0 +1,10 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
+
+public record Batter(
+        Topping topping,
+        int quantityInGrams,
+        int targetCookieCount
+) {
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCleanupRequest.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCleanupRequest.java
new file mode 100644
index 0000000..26a9ea7
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCleanupRequest.java
@@ -0,0 +1,4 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+public record BatterCleanupRequest(String orderId) {
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java
new file mode 100644
index 0000000..38cc0c1
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCreationRequest.java
@@ -0,0 +1,11 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
+
+public record BatterCreationRequest(
+        String orderId,
+        Topping targetTopping,
+        int targetCookieCount
+) {
+
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCreationResult.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCreationResult.java
new file mode 100644
index 0000000..d75e6ab
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/batter/dtos/BatterCreationResult.java
@@ -0,0 +1,5 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+public record BatterCreationResult(Batter batter) {
+
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenApp.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenApp.java
new file mode 100644
index 0000000..4c57367
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenApp.java
@@ -0,0 +1,13 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.worker.Worker;
+
+public class KitchenApp {
+    public static void main(String[] args) {
+        Worker worker = TemporalUtils.newWorker(TemporalQueues.KITCHEN);
+        worker.registerWorkflowImplementationTypes(KitchenWorkflowImpl.class);
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenWorkflow.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenWorkflow.java
new file mode 100644
index 0000000..ca26635
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenWorkflow.java
@@ -0,0 +1,21 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
+import io.temporal.workflow.QueryMethod;
+import io.temporal.workflow.SignalMethod;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+
+@WorkflowInterface
+public interface KitchenWorkflow {
+    @WorkflowMethod
+    CookieOrderResult makeCookies(CookieOrderRequest request);
+
+    @SignalMethod
+    void ovenReady();
+
+    @QueryMethod
+    CookieOrderStatus getStatus();
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
new file mode 100644
index 0000000..ef842cf
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/KitchenWorkflowImpl.java
@@ -0,0 +1,72 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.bake.BakeService;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.batter.BatterService;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCleanupRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
+import io.takima.temporalpractice.bakery.temporal.TemporalActivityFactory;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.temporal.failure.ActivityFailure;
+import io.temporal.workflow.Saga;
+import io.temporal.workflow.Workflow;
+import org.slf4j.Logger;
+
+import java.time.Duration;
+import java.util.List;
+
+public class KitchenWorkflowImpl implements KitchenWorkflow {
+    private final BatterService batterService;
+    private final BakeService bakeService;
+    private boolean ovenReady = false;
+    private CookieOrderRequest cookieOrder;
+
+    private final Logger logger = Workflow.getLogger(KitchenWorkflowImpl.class);
+
+    private final Saga saga = new Saga(new Saga.Options.Builder().build());
+
+    public KitchenWorkflowImpl() {
+        this.batterService = TemporalActivityFactory.newActivityStub(BatterService.class, TemporalQueues.BATTER);
+        this.bakeService = TemporalActivityFactory.newActivityStub(BakeService.class, TemporalQueues.BAKE);
+    }
+
+
+    @Override
+    public CookieOrderResult makeCookies(CookieOrderRequest request) {
+        this.cookieOrder = request;
+        var timer = Workflow.newTimer(Duration.ofSeconds(30));
+
+        try {
+            saga.addCompensation(batterService::cleanupBatterIfNeeded, new BatterCleanupRequest(request.orderId()));
+
+            logger.info("Order {}: Starting to prepare {} cookies with topping {} and baking preference {}", request.orderId(), request.quantity(), request.topping(), request.bakingPreference());
+            var batterCreationResult = batterService.prepareBatter(new BatterCreationRequest(request.orderId(), request.topping(), request.quantity()));
+            var batter = batterCreationResult.batter();
+
+            Workflow.await(() -> ovenReady);
+
+            var bakeResult = bakeService.bake(new BakeRequest(request.orderId(), batter, request.bakingPreference()));
+
+            logger.info("Order {}: Your {} cookies are ready!", request.orderId(), bakeResult.cookies().size());
+
+            timer.get();
+            return new CookieOrderResult(request.orderId(), bakeResult.cookies());
+        } catch (ActivityFailure failures) {
+            saga.compensate();
+            return new CookieOrderResult(request.orderId(), List.of());
+        }
+    }
+
+    @Override
+    public void ovenReady() {
+        this.ovenReady = true;
+    }
+
+    @Override
+    public CookieOrderStatus getStatus() {
+        return new CookieOrderStatus(ovenReady, cookieOrder);
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java
new file mode 100644
index 0000000..f82ef2e
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/kitchen/dtos/KitchenDtos.java
@@ -0,0 +1,62 @@
+package io.takima.temporalpractice.bakery.kitchen.dtos;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface KitchenDtos {
+    enum BakingPreference {
+        RAW,
+        SOFT,
+        COOKED,
+        BURNT;
+
+        public static BakingPreference random() {
+            return values()[(int) (Math.random() * values().length)];
+        }
+    }
+
+    enum Topping {
+        CHOCOLATE,
+        NUTS,
+        NONE;
+
+        public static Topping random() {
+            return values()[(int) (Math.random() * values().length)];
+        }
+    }
+
+    record Cookie(
+            BakingPreference bakingPreference,
+            Topping topping
+    ) {
+    }
+
+    record CookieOrderRequest(
+            String orderId,
+            int quantity,
+            BakingPreference bakingPreference,
+            Topping topping
+    ) {
+
+        public static CookieOrderRequest random() {
+            return new CookieOrderRequest(
+                    UUID.randomUUID().toString(),
+                    (int) (Math.random() * 10) + 1,
+                    BakingPreference.random(),
+                    Topping.random()
+            );
+        }
+    }
+
+    record CookieOrderResult(
+            String orderId,
+            List<Cookie> cookies
+    ) {
+    }
+
+    record CookieOrderStatus(
+            boolean ovenReady,
+            CookieOrderRequest request
+    ) {
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalActivityFactory.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalActivityFactory.java
new file mode 100644
index 0000000..ec51a0e
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalActivityFactory.java
@@ -0,0 +1,20 @@
+package io.takima.temporalpractice.bakery.temporal;
+
+import io.temporal.activity.ActivityOptions;
+import io.temporal.common.RetryOptions;
+import io.temporal.workflow.Workflow;
+
+import java.time.Duration;
+
+public class TemporalActivityFactory {
+    public static <T> T newActivityStub(Class<T> workflowInterface, String queue) {
+        return Workflow.newActivityStub(
+                workflowInterface,
+                ActivityOptions.newBuilder()
+                        .setTaskQueue(queue)
+                        .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(2).build())
+                        .setStartToCloseTimeout(Duration.ofSeconds(5))
+                        .build()
+        );
+    }
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalQueues.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalQueues.java
new file mode 100644
index 0000000..0c99053
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalQueues.java
@@ -0,0 +1,7 @@
+package io.takima.temporalpractice.bakery.temporal;
+
+public class TemporalQueues {
+  public static final String KITCHEN = "kitchen";
+  public static final String BATTER = "batter";
+  public static final String BAKE = "bake";
+}
diff --git a/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalUtils.java b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalUtils.java
new file mode 100644
index 0000000..101f7e6
--- /dev/null
+++ b/solutions/day2/part-1.3/main/java/io/takima/temporalpractice/bakery/temporal/TemporalUtils.java
@@ -0,0 +1,36 @@
+package io.takima.temporalpractice.bakery.temporal;
+
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerFactory;
+
+public class TemporalUtils {
+
+    // Represents the connection to your local cluster. For now, lets keep it simple
+    private static final WorkflowServiceStubs SERVICE_STUBS = WorkflowServiceStubs.newLocalServiceStubs();
+
+    // Your key for interacting with the Temporal world.
+    public static final WorkflowClient CLIENT = WorkflowClient.newInstance(SERVICE_STUBS);
+
+    private static final WorkerFactory FACTORY = WorkerFactory.newInstance(CLIENT);
+
+    public static Worker newWorker(String queue) {
+        return FACTORY.newWorker(queue);
+    }
+
+    public static void startWorkerFactory() {
+        FACTORY.start();
+    }
+
+    public static <T> T newWorkflowStub(Class<T> workflowInterface, String queue, String workflowId) {
+        return CLIENT.newWorkflowStub(
+                workflowInterface,
+                WorkflowOptions.newBuilder()
+                        .setTaskQueue(queue)
+                        .setWorkflowId(workflowId)
+                        .build()
+        );
+    }
+}
diff --git a/solutions/day2/part-1.3/main/resources/application.yml b/solutions/day2/part-1.3/main/resources/application.yml
new file mode 100644
index 0000000..13906e5
--- /dev/null
+++ b/solutions/day2/part-1.3/main/resources/application.yml
@@ -0,0 +1,3 @@
+spring:
+  application:
+    name: Temporal Practice
diff --git a/solutions/day2/part-1.3/test/java/io/takima/temporalpractice/bakery/cookie/CookieWorkflowTest.java b/solutions/day2/part-1.3/test/java/io/takima/temporalpractice/bakery/cookie/CookieWorkflowTest.java
new file mode 100644
index 0000000..748902f
--- /dev/null
+++ b/solutions/day2/part-1.3/test/java/io/takima/temporalpractice/bakery/cookie/CookieWorkflowTest.java
@@ -0,0 +1,122 @@
+package io.takima.temporalpractice.bakery.cookie;
+
+import io.takima.temporalpractice.bakery.bake.BakeService;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
+import io.takima.temporalpractice.bakery.batter.BatterService;
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCleanupRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflowImpl;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.temporal.client.WorkflowClient;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.time.Duration;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class CookieWorkflowTest {
+
+    @Mock(withoutAnnotations = true)
+    private BakeService bakeService;
+
+    @Mock(withoutAnnotations = true)
+    private BatterService batterService;
+
+
+    @RegisterExtension
+    public static final TestWorkflowExtension testWorkflowExtension =
+            TestWorkflowExtension.newBuilder()
+                    .registerWorkflowImplementationTypes(KitchenWorkflowImpl.class)
+                    .setDoNotStart(true)
+                    .build();
+
+    @BeforeEach
+    void init(TestWorkflowEnvironment testEnv) {
+        testEnv.newWorker(TemporalQueues.BAKE)
+                .registerActivitiesImplementations(bakeService);
+        testEnv.newWorker(TemporalQueues.BATTER)
+                .registerActivitiesImplementations(batterService);
+        testEnv.start();
+    }
+
+    KitchenDtos.CookieOrderRequest request = KitchenDtos.CookieOrderRequest.random();
+    BatterCreationRequest batterCreationRequest = new BatterCreationRequest(request.orderId(), request.topping(), request.quantity());
+    BatterCreationResult batterCreationResult = new BatterCreationResult(new Batter(request.topping(), 30 * request.quantity(), request.quantity()));
+    BakeRequest bakeRequest = new BakeRequest(request.orderId(), batterCreationResult.batter(), request.bakingPreference());
+    BakeResult bakeResult = new BakeResult(List.of(new KitchenDtos.Cookie(request.bakingPreference(), request.topping())));
+
+    @Test
+    public void shouldCleanupBatter(
+            // Test environment for configuration
+            TestWorkflowEnvironment testEnv,
+            // Auto-created Workflow stub
+            KitchenWorkflow workflow
+    ) {
+        WorkflowClient.start(workflow::makeCookies, request);
+
+        when(batterService.prepareBatter(batterCreationRequest))
+                .thenReturn(batterCreationResult);
+        workflow.ovenReady();
+        when(bakeService.bake(bakeRequest))
+                .thenThrow(new RuntimeException("I will always fail"));
+
+        var result = workflow.makeCookies(request);
+
+        verify(batterService).cleanupBatterIfNeeded(new BatterCleanupRequest(request.orderId()));
+        assertThat(result.orderId()).isEqualTo(request.orderId());
+        assertThat(result.cookies()).isEmpty();
+    }
+
+    @Test
+    public void shouldMakeCookies(
+            // Test environment for configuration
+            TestWorkflowEnvironment testEnv,
+            // Auto-created Workflow stub
+            KitchenWorkflow workflow
+    ) {
+        // get the env starting time
+        var startTime = testEnv.currentTimeMillis();
+
+        // Start the workflow asynchronously
+        WorkflowClient.start(workflow::makeCookies, request);
+        when(batterService.prepareBatter(batterCreationRequest))
+                .thenThrow(new RuntimeException("I failed on first try"))
+                .thenReturn(batterCreationResult);
+        // Make sure we dont bake before the oven is ready
+        verifyNoInteractions(bakeService);
+
+        var status = workflow.getStatus();
+        assertThat(status.ovenReady()).isFalse();
+        assertThat(status.request()).isEqualTo(request);
+
+        workflow.ovenReady();
+        status = workflow.getStatus();
+        assertThat(status.ovenReady()).isTrue();
+        when(bakeService.bake(bakeRequest)).thenReturn(bakeResult);
+
+        // Get the workflow result
+        var result = workflow.makeCookies(request);
+
+        assertThat(result.orderId()).isEqualTo(request.orderId());
+        assertThat(result.cookies())
+                .isEqualTo(bakeResult.cookies());
+
+        var duration = Duration.ofMillis(testEnv.currentTimeMillis() - startTime);
+        assertThat(duration).isGreaterThan(Duration.ofSeconds(30));
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/OrderCookiesApp.java b/solutions/day2/part-2.1/bakery/OrderCookiesApp.java
new file mode 100644
index 0000000..2ff2b24
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/OrderCookiesApp.java
@@ -0,0 +1,25 @@
+package io.takima.temporalpractice.bakery;
+
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+
+public class OrderCookiesApp {
+    public static void main(String[] args) {
+        // This app simulates an order of cookies
+        // It should call the workflow which makes cookies
+        var orderRequest = CookieOrderRequest.random();
+
+        KitchenWorkflow workflow = TemporalUtils.newWorkflowStub(
+                KitchenWorkflow.class,
+                TemporalQueues.KITCHEN,
+                "kitchen-" + orderRequest.orderId()
+        );
+
+        workflow.makeCookies(orderRequest); // Start the Workflow Execution
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/OrderManyCookies.java b/solutions/day2/part-2.1/bakery/OrderManyCookies.java
new file mode 100644
index 0000000..6421088
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/OrderManyCookies.java
@@ -0,0 +1,70 @@
+package io.takima.temporalpractice.bakery;
+
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.api.enums.v1.ParentClosePolicy;
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.workflow.*;
+import org.slf4j.Logger;
+
+import java.time.Duration;
+
+public class OrderManyCookies {
+    public static void main(String[] args) {
+        var queue = "manycookies";
+
+        TemporalUtils.newWorker(queue)
+                .registerWorkflowImplementationTypes(ManyCookiesImpl.class);
+
+        TemporalUtils.startWorkerFactory();
+
+        try {
+            ManyCookies manyCookies = TemporalUtils.CLIENT.newWorkflowStub(
+                    ManyCookies.class,
+                    WorkflowOptions.newBuilder().setWorkflowId("cookie-orderer").setTaskQueue(queue).build()
+            );
+            WorkflowClient.start(manyCookies::continuousOrders);
+        } catch (Exception e) {
+            System.out.println("Many cookies already running, skipping...");
+        }
+    }
+
+    public static class ManyCookiesImpl implements ManyCookies {
+
+        private static final Logger logger = Workflow.getLogger(ManyCookiesImpl.class);
+
+        @Override
+        public void continuousOrders() {
+
+            var options = ChildWorkflowOptions.newBuilder()
+                    .setWorkflowId("order-" + Workflow.randomUUID())
+                    .setTaskQueue(TemporalQueues.KITCHEN)
+                    .setParentClosePolicy(ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON)
+                    .build();
+            var kitchenWorkflow = Workflow.newChildWorkflowStub(KitchenWorkflow.class, options);
+
+            var quantity = Workflow.newRandom().nextInt(1, 5);
+            var baking = KitchenDtos.BakingPreference.values()[Workflow.newRandom().nextInt(KitchenDtos.BakingPreference.values().length)];
+            var topping = KitchenDtos.Topping.values()[Workflow.newRandom().nextInt(KitchenDtos.Topping.values().length)];
+
+            var cookiesPreferences = new KitchenDtos.CookieOrderRequest(Workflow.randomUUID().toString(), quantity, baking, topping);
+
+            logger.info("Ordering cookies\n{}", cookiesPreferences);
+            Async.function(kitchenWorkflow::makeCookies, cookiesPreferences);
+
+            Workflow.sleep(Duration.ofSeconds(10));
+            kitchenWorkflow.ovenReady();
+
+            Workflow.continueAsNew();
+        }
+    }
+
+    @WorkflowInterface
+    public interface ManyCookies {
+        @WorkflowMethod
+        void continuousOrders();
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/bake/BakeApp.java b/solutions/day2/part-2.1/bakery/bake/BakeApp.java
new file mode 100644
index 0000000..2d1cdb1
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/bake/BakeApp.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+
+public class BakeApp {
+    public static void main(String[] args) {
+        var worker = TemporalUtils.newWorker(TemporalQueues.BAKE);
+        worker.registerActivitiesImplementations(new BakeServiceImpl());
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/bake/BakeService.java b/solutions/day2/part-2.1/bakery/bake/BakeService.java
new file mode 100644
index 0000000..36c0d02
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/bake/BakeService.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityMethod;
+
+@ActivityInterface
+public interface BakeService {
+    @ActivityMethod
+    BakeResult bake(BakeRequest request);
+}
diff --git a/solutions/day2/part-2.1/bakery/bake/BakeServiceImpl.java b/solutions/day2/part-2.1/bakery/bake/BakeServiceImpl.java
new file mode 100644
index 0000000..22509b6
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/bake/BakeServiceImpl.java
@@ -0,0 +1,22 @@
+package io.takima.temporalpractice.bakery.bake;
+
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Cookie;
+
+import java.util.ArrayList;
+
+public class BakeServiceImpl implements BakeService {
+  @Override
+  public BakeResult bake(BakeRequest request) {
+    System.out.println("Will bake those cookies " + request.bakingPreference());
+    var cookies = new ArrayList<Cookie>();
+    for (int i = 0; i < request.batter().targetCookieCount(); i++) {
+      // Making cookies out of batter
+      var cookie = new Cookie(request.bakingPreference(), request.batter().topping());
+      // Add it to the cookies after it is baked
+      cookies.add(cookie);
+    }
+    return new BakeResult(cookies);
+  }
+}
diff --git a/solutions/day2/part-2.1/bakery/bake/dtos/BakeRequest.java b/solutions/day2/part-2.1/bakery/bake/dtos/BakeRequest.java
new file mode 100644
index 0000000..42701fe
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/bake/dtos/BakeRequest.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.bake.dtos;
+
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.BakingPreference;
+
+public record BakeRequest(
+        String orderId,
+        Batter batter,
+        BakingPreference bakingPreference
+) {
+}
+
diff --git a/solutions/day2/part-2.1/bakery/bake/dtos/BakeResult.java b/solutions/day2/part-2.1/bakery/bake/dtos/BakeResult.java
new file mode 100644
index 0000000..f9afcf7
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/bake/dtos/BakeResult.java
@@ -0,0 +1,8 @@
+package io.takima.temporalpractice.bakery.bake.dtos;
+
+import java.util.List;
+
+import static io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Cookie;
+
+public record BakeResult(List<Cookie> cookies) {
+}
diff --git a/solutions/day2/part-2.1/bakery/batter/BatterApp.java b/solutions/day2/part-2.1/bakery/batter/BatterApp.java
new file mode 100644
index 0000000..8b4bdb9
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/batter/BatterApp.java
@@ -0,0 +1,12 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+
+public class BatterApp {
+    public static void main(String[] args) {
+        var worker = TemporalUtils.newWorker(TemporalQueues.BATTER);
+        worker.registerActivitiesImplementations(new BatterServiceImpl());
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/batter/BatterService.java b/solutions/day2/part-2.1/bakery/batter/BatterService.java
new file mode 100644
index 0000000..1353c54
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/batter/BatterService.java
@@ -0,0 +1,17 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCleanupRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+import io.temporal.activity.ActivityInterface;
+import io.temporal.activity.ActivityMethod;
+
+@ActivityInterface
+public interface BatterService {
+
+    @ActivityMethod
+    BatterCreationResult prepareBatter(BatterCreationRequest request);
+
+    @ActivityMethod
+    void cleanupBatterIfNeeded(BatterCleanupRequest request);
+}
diff --git a/solutions/day2/part-2.1/bakery/batter/BatterServiceImpl.java b/solutions/day2/part-2.1/bakery/batter/BatterServiceImpl.java
new file mode 100644
index 0000000..17a2e83
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/batter/BatterServiceImpl.java
@@ -0,0 +1,27 @@
+package io.takima.temporalpractice.bakery.batter;
+
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCleanupRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+
+public class BatterServiceImpl implements BatterService {
+
+    static final int BATTER_QTY_PER_COOKIE_IN_GRAMS = 30; // in grams
+
+    @Override
+    public BatterCreationResult prepareBatter(BatterCreationRequest request) {
+        System.out.println("Mixing flour, sugar, and love for " + request.targetCookieCount() + " cookies with topping " + request.targetTopping());
+        return new BatterCreationResult(
+                new Batter(
+                        request.targetTopping(),
+                        BATTER_QTY_PER_COOKIE_IN_GRAMS * request.targetCookieCount(),
+                        request.targetCookieCount()
+                ));
+    }
+
+    @Override
+    public void cleanupBatterIfNeeded(BatterCleanupRequest request) {
+        System.out.println("Cleaning up batter of order " + request.orderId());
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/batter/dtos/Batter.java b/solutions/day2/part-2.1/bakery/batter/dtos/Batter.java
new file mode 100644
index 0000000..8608c0e
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/batter/dtos/Batter.java
@@ -0,0 +1,10 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
+
+public record Batter(
+        Topping topping,
+        int quantityInGrams,
+        int targetCookieCount
+) {
+}
diff --git a/solutions/day2/part-2.1/bakery/batter/dtos/BatterCleanupRequest.java b/solutions/day2/part-2.1/bakery/batter/dtos/BatterCleanupRequest.java
new file mode 100644
index 0000000..26a9ea7
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/batter/dtos/BatterCleanupRequest.java
@@ -0,0 +1,4 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+public record BatterCleanupRequest(String orderId) {
+}
diff --git a/solutions/day2/part-2.1/bakery/batter/dtos/BatterCreationRequest.java b/solutions/day2/part-2.1/bakery/batter/dtos/BatterCreationRequest.java
new file mode 100644
index 0000000..38cc0c1
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/batter/dtos/BatterCreationRequest.java
@@ -0,0 +1,11 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.Topping;
+
+public record BatterCreationRequest(
+        String orderId,
+        Topping targetTopping,
+        int targetCookieCount
+) {
+
+}
diff --git a/solutions/day2/part-2.1/bakery/batter/dtos/BatterCreationResult.java b/solutions/day2/part-2.1/bakery/batter/dtos/BatterCreationResult.java
new file mode 100644
index 0000000..d75e6ab
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/batter/dtos/BatterCreationResult.java
@@ -0,0 +1,5 @@
+package io.takima.temporalpractice.bakery.batter.dtos;
+
+public record BatterCreationResult(Batter batter) {
+
+}
diff --git a/solutions/day2/part-2.1/bakery/kitchen/KitchenApp.java b/solutions/day2/part-2.1/bakery/kitchen/KitchenApp.java
new file mode 100644
index 0000000..52854d1
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/kitchen/KitchenApp.java
@@ -0,0 +1,14 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.takima.temporalpractice.bakery.temporal.TemporalUtils;
+import io.temporal.worker.Worker;
+
+public class KitchenApp {
+    public static void main(String[] args) {
+        Worker worker = TemporalUtils.newWorker(TemporalQueues.KITCHEN);
+        worker.registerWorkflowImplementationTypes(KitchenWorkflowImpl.class);
+        worker.registerWorkflowImplementationTypes(KitchenWorkflowImplLegacy.class);
+        TemporalUtils.startWorkerFactory();
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflow.java b/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflow.java
new file mode 100644
index 0000000..4a48a8e
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflow.java
@@ -0,0 +1,23 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
+import io.temporal.workflow.QueryMethod;
+import io.temporal.workflow.SignalMethod;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+
+@WorkflowInterface
+public interface KitchenWorkflow {
+    String Type = "CookieOrderWorkflowV2";
+
+    @WorkflowMethod(name = Type)
+    CookieOrderResult makeCookies(CookieOrderRequest request);
+
+    @SignalMethod
+    void ovenReady();
+
+    @QueryMethod
+    CookieOrderStatus getStatus();
+}
diff --git a/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowImpl.java b/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowImpl.java
new file mode 100644
index 0000000..ef842cf
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowImpl.java
@@ -0,0 +1,72 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.bake.BakeService;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.batter.BatterService;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCleanupRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
+import io.takima.temporalpractice.bakery.temporal.TemporalActivityFactory;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.temporal.failure.ActivityFailure;
+import io.temporal.workflow.Saga;
+import io.temporal.workflow.Workflow;
+import org.slf4j.Logger;
+
+import java.time.Duration;
+import java.util.List;
+
+public class KitchenWorkflowImpl implements KitchenWorkflow {
+    private final BatterService batterService;
+    private final BakeService bakeService;
+    private boolean ovenReady = false;
+    private CookieOrderRequest cookieOrder;
+
+    private final Logger logger = Workflow.getLogger(KitchenWorkflowImpl.class);
+
+    private final Saga saga = new Saga(new Saga.Options.Builder().build());
+
+    public KitchenWorkflowImpl() {
+        this.batterService = TemporalActivityFactory.newActivityStub(BatterService.class, TemporalQueues.BATTER);
+        this.bakeService = TemporalActivityFactory.newActivityStub(BakeService.class, TemporalQueues.BAKE);
+    }
+
+
+    @Override
+    public CookieOrderResult makeCookies(CookieOrderRequest request) {
+        this.cookieOrder = request;
+        var timer = Workflow.newTimer(Duration.ofSeconds(30));
+
+        try {
+            saga.addCompensation(batterService::cleanupBatterIfNeeded, new BatterCleanupRequest(request.orderId()));
+
+            logger.info("Order {}: Starting to prepare {} cookies with topping {} and baking preference {}", request.orderId(), request.quantity(), request.topping(), request.bakingPreference());
+            var batterCreationResult = batterService.prepareBatter(new BatterCreationRequest(request.orderId(), request.topping(), request.quantity()));
+            var batter = batterCreationResult.batter();
+
+            Workflow.await(() -> ovenReady);
+
+            var bakeResult = bakeService.bake(new BakeRequest(request.orderId(), batter, request.bakingPreference()));
+
+            logger.info("Order {}: Your {} cookies are ready!", request.orderId(), bakeResult.cookies().size());
+
+            timer.get();
+            return new CookieOrderResult(request.orderId(), bakeResult.cookies());
+        } catch (ActivityFailure failures) {
+            saga.compensate();
+            return new CookieOrderResult(request.orderId(), List.of());
+        }
+    }
+
+    @Override
+    public void ovenReady() {
+        this.ovenReady = true;
+    }
+
+    @Override
+    public CookieOrderStatus getStatus() {
+        return new CookieOrderStatus(ovenReady, cookieOrder);
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowImplLegacy.java b/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowImplLegacy.java
new file mode 100644
index 0000000..e58630f
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowImplLegacy.java
@@ -0,0 +1,73 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.bake.BakeService;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.batter.BatterService;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCleanupRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
+import io.takima.temporalpractice.bakery.temporal.TemporalActivityFactory;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.temporal.failure.ActivityFailure;
+import io.temporal.workflow.Saga;
+import io.temporal.workflow.Workflow;
+import org.slf4j.Logger;
+
+import java.time.Duration;
+import java.util.List;
+
+@Deprecated
+public class KitchenWorkflowImplLegacy implements KitchenWorkflowLegacy {
+    private final BatterService batterService;
+    private final BakeService bakeService;
+    private boolean ovenReady = false;
+    private CookieOrderRequest cookieOrder;
+
+    private final Logger logger = Workflow.getLogger(KitchenWorkflowImplLegacy.class);
+
+    private final Saga saga = new Saga(new Saga.Options.Builder().build());
+
+    public KitchenWorkflowImplLegacy() {
+        this.batterService = TemporalActivityFactory.newActivityStub(BatterService.class, TemporalQueues.BATTER);
+        this.bakeService = TemporalActivityFactory.newActivityStub(BakeService.class, TemporalQueues.BAKE);
+    }
+
+
+    @Override
+    public CookieOrderResult makeCookies(CookieOrderRequest request) {
+        this.cookieOrder = request;
+        var timer = Workflow.newTimer(Duration.ofSeconds(30));
+
+        try {
+            saga.addCompensation(batterService::cleanupBatterIfNeeded, new BatterCleanupRequest(request.orderId()));
+
+            logger.info("Order {}: Starting to prepare {} cookies with topping {} and baking preference {}", request.orderId(), request.quantity(), request.topping(), request.bakingPreference());
+            var batterCreationResult = batterService.prepareBatter(new BatterCreationRequest(request.orderId(), request.topping(), request.quantity()));
+            var batter = batterCreationResult.batter();
+
+            Workflow.await(() -> ovenReady);
+
+            var bakeResult = bakeService.bake(new BakeRequest(request.orderId(), batter, request.bakingPreference()));
+
+            logger.info("Order {}: Your {} cookies are ready!", request.orderId(), bakeResult.cookies().size());
+
+            timer.get();
+            return new CookieOrderResult(request.orderId(), bakeResult.cookies());
+        } catch (ActivityFailure failures) {
+            saga.compensate();
+            return new CookieOrderResult(request.orderId(), List.of());
+        }
+    }
+
+    @Override
+    public void ovenReady() {
+        this.ovenReady = true;
+    }
+
+    @Override
+    public CookieOrderStatus getStatus() {
+        return new CookieOrderStatus(ovenReady, cookieOrder);
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowLegacy.java b/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowLegacy.java
new file mode 100644
index 0000000..a6c3f98
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/kitchen/KitchenWorkflowLegacy.java
@@ -0,0 +1,24 @@
+package io.takima.temporalpractice.bakery.kitchen;
+
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderRequest;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderResult;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos.CookieOrderStatus;
+import io.temporal.workflow.QueryMethod;
+import io.temporal.workflow.SignalMethod;
+import io.temporal.workflow.WorkflowInterface;
+import io.temporal.workflow.WorkflowMethod;
+
+@Deprecated
+@WorkflowInterface
+public interface KitchenWorkflowLegacy {
+    String Type = "CookieOrderWorkflow";
+
+    @WorkflowMethod(name = Type)
+    CookieOrderResult makeCookies(CookieOrderRequest request);
+
+    @SignalMethod
+    void ovenReady();
+
+    @QueryMethod
+    CookieOrderStatus getStatus();
+}
diff --git a/solutions/day2/part-2.1/bakery/kitchen/dtos/KitchenDtos.java b/solutions/day2/part-2.1/bakery/kitchen/dtos/KitchenDtos.java
new file mode 100644
index 0000000..f82ef2e
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/kitchen/dtos/KitchenDtos.java
@@ -0,0 +1,62 @@
+package io.takima.temporalpractice.bakery.kitchen.dtos;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface KitchenDtos {
+    enum BakingPreference {
+        RAW,
+        SOFT,
+        COOKED,
+        BURNT;
+
+        public static BakingPreference random() {
+            return values()[(int) (Math.random() * values().length)];
+        }
+    }
+
+    enum Topping {
+        CHOCOLATE,
+        NUTS,
+        NONE;
+
+        public static Topping random() {
+            return values()[(int) (Math.random() * values().length)];
+        }
+    }
+
+    record Cookie(
+            BakingPreference bakingPreference,
+            Topping topping
+    ) {
+    }
+
+    record CookieOrderRequest(
+            String orderId,
+            int quantity,
+            BakingPreference bakingPreference,
+            Topping topping
+    ) {
+
+        public static CookieOrderRequest random() {
+            return new CookieOrderRequest(
+                    UUID.randomUUID().toString(),
+                    (int) (Math.random() * 10) + 1,
+                    BakingPreference.random(),
+                    Topping.random()
+            );
+        }
+    }
+
+    record CookieOrderResult(
+            String orderId,
+            List<Cookie> cookies
+    ) {
+    }
+
+    record CookieOrderStatus(
+            boolean ovenReady,
+            CookieOrderRequest request
+    ) {
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/temporal/TemporalActivityFactory.java b/solutions/day2/part-2.1/bakery/temporal/TemporalActivityFactory.java
new file mode 100644
index 0000000..ec51a0e
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/temporal/TemporalActivityFactory.java
@@ -0,0 +1,20 @@
+package io.takima.temporalpractice.bakery.temporal;
+
+import io.temporal.activity.ActivityOptions;
+import io.temporal.common.RetryOptions;
+import io.temporal.workflow.Workflow;
+
+import java.time.Duration;
+
+public class TemporalActivityFactory {
+    public static <T> T newActivityStub(Class<T> workflowInterface, String queue) {
+        return Workflow.newActivityStub(
+                workflowInterface,
+                ActivityOptions.newBuilder()
+                        .setTaskQueue(queue)
+                        .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(2).build())
+                        .setStartToCloseTimeout(Duration.ofSeconds(5))
+                        .build()
+        );
+    }
+}
diff --git a/solutions/day2/part-2.1/bakery/temporal/TemporalQueues.java b/solutions/day2/part-2.1/bakery/temporal/TemporalQueues.java
new file mode 100644
index 0000000..0c99053
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/temporal/TemporalQueues.java
@@ -0,0 +1,7 @@
+package io.takima.temporalpractice.bakery.temporal;
+
+public class TemporalQueues {
+  public static final String KITCHEN = "kitchen";
+  public static final String BATTER = "batter";
+  public static final String BAKE = "bake";
+}
diff --git a/solutions/day2/part-2.1/bakery/temporal/TemporalUtils.java b/solutions/day2/part-2.1/bakery/temporal/TemporalUtils.java
new file mode 100644
index 0000000..101f7e6
--- /dev/null
+++ b/solutions/day2/part-2.1/bakery/temporal/TemporalUtils.java
@@ -0,0 +1,36 @@
+package io.takima.temporalpractice.bakery.temporal;
+
+import io.temporal.client.WorkflowClient;
+import io.temporal.client.WorkflowOptions;
+import io.temporal.serviceclient.WorkflowServiceStubs;
+import io.temporal.worker.Worker;
+import io.temporal.worker.WorkerFactory;
+
+public class TemporalUtils {
+
+    // Represents the connection to your local cluster. For now, lets keep it simple
+    private static final WorkflowServiceStubs SERVICE_STUBS = WorkflowServiceStubs.newLocalServiceStubs();
+
+    // Your key for interacting with the Temporal world.
+    public static final WorkflowClient CLIENT = WorkflowClient.newInstance(SERVICE_STUBS);
+
+    private static final WorkerFactory FACTORY = WorkerFactory.newInstance(CLIENT);
+
+    public static Worker newWorker(String queue) {
+        return FACTORY.newWorker(queue);
+    }
+
+    public static void startWorkerFactory() {
+        FACTORY.start();
+    }
+
+    public static <T> T newWorkflowStub(Class<T> workflowInterface, String queue, String workflowId) {
+        return CLIENT.newWorkflowStub(
+                workflowInterface,
+                WorkflowOptions.newBuilder()
+                        .setTaskQueue(queue)
+                        .setWorkflowId(workflowId)
+                        .build()
+        );
+    }
+}
diff --git a/solutions/day2/part-2.2/test/java/io/takima/temporalpractice/.gitkeep b/solutions/day2/part-2.2/test/java/io/takima/temporalpractice/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/solutions/day2/part-2.2/test/java/io/takima/temporalpractice/bakery/cookie/CookieWorkflowTest.java b/solutions/day2/part-2.2/test/java/io/takima/temporalpractice/bakery/cookie/CookieWorkflowTest.java
new file mode 100644
index 0000000..aed1a85
--- /dev/null
+++ b/solutions/day2/part-2.2/test/java/io/takima/temporalpractice/bakery/cookie/CookieWorkflowTest.java
@@ -0,0 +1,130 @@
+package io.takima.temporalpractice.bakery.cookie;
+
+import io.takima.temporalpractice.bakery.bake.BakeService;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeRequest;
+import io.takima.temporalpractice.bakery.bake.dtos.BakeResult;
+import io.takima.temporalpractice.bakery.batter.BatterService;
+import io.takima.temporalpractice.bakery.batter.dtos.Batter;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCleanupRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationRequest;
+import io.takima.temporalpractice.bakery.batter.dtos.BatterCreationResult;
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflow;
+import io.takima.temporalpractice.bakery.kitchen.KitchenWorkflowImpl;
+import io.takima.temporalpractice.bakery.kitchen.dtos.KitchenDtos;
+import io.takima.temporalpractice.bakery.temporal.TemporalQueues;
+import io.temporal.client.WorkflowClient;
+import io.temporal.testing.TestWorkflowEnvironment;
+import io.temporal.testing.TestWorkflowExtension;
+import io.temporal.testing.WorkflowReplayer;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.io.File;
+import java.time.Duration;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class CookieWorkflowTest {
+
+    @Mock(withoutAnnotations = true)
+    private BakeService bakeService;
+
+    @Mock(withoutAnnotations = true)
+    private BatterService batterService;
+
+
+    @RegisterExtension
+    public static final TestWorkflowExtension testWorkflowExtension =
+            TestWorkflowExtension.newBuilder()
+                    .registerWorkflowImplementationTypes(KitchenWorkflowImpl.class)
+                    .setDoNotStart(true)
+                    .build();
+
+    @BeforeEach
+    void init(TestWorkflowEnvironment testEnv) {
+        testEnv.newWorker(TemporalQueues.BAKE)
+                .registerActivitiesImplementations(bakeService);
+        testEnv.newWorker(TemporalQueues.BATTER)
+                .registerActivitiesImplementations(batterService);
+        testEnv.start();
+    }
+
+    KitchenDtos.CookieOrderRequest request = KitchenDtos.CookieOrderRequest.random();
+    BatterCreationRequest batterCreationRequest = new BatterCreationRequest(request.orderId(), request.topping(), request.quantity());
+    BatterCreationResult batterCreationResult = new BatterCreationResult(new Batter(request.topping(), 30 * request.quantity(), request.quantity()));
+    BakeRequest bakeRequest = new BakeRequest(request.orderId(), batterCreationResult.batter(), request.bakingPreference());
+    BakeResult bakeResult = new BakeResult(List.of(new KitchenDtos.Cookie(request.bakingPreference(), request.topping())));
+
+    @Test
+    public void shouldCleanupBatter(
+            // Test environment for configuration
+            TestWorkflowEnvironment testEnv,
+            // Auto-created Workflow stub
+            KitchenWorkflow workflow
+    ) {
+        WorkflowClient.start(workflow::makeCookies, request);
+
+        when(batterService.prepareBatter(batterCreationRequest))
+                .thenReturn(batterCreationResult);
+        workflow.ovenReady();
+        when(bakeService.bake(bakeRequest))
+                .thenThrow(new RuntimeException("I will always fail"));
+
+        var result = workflow.makeCookies(request);
+
+        verify(batterService).cleanupBatterIfNeeded(new BatterCleanupRequest(request.orderId()));
+        assertThat(result.orderId()).isEqualTo(request.orderId());
+        assertThat(result.cookies()).isEmpty();
+    }
+
+    @Test
+    public void shouldMakeCookies(
+            // Test environment for configuration
+            TestWorkflowEnvironment testEnv,
+            // Auto-created Workflow stub
+            KitchenWorkflow workflow
+    ) {
+        // get the env starting time
+        var startTime = testEnv.currentTimeMillis();
+
+        // Start the workflow asynchronously
+        WorkflowClient.start(workflow::makeCookies, request);
+        when(batterService.prepareBatter(batterCreationRequest))
+                .thenThrow(new RuntimeException("I failed on first try"))
+                .thenReturn(batterCreationResult);
+        // Make sure we dont bake before the oven is ready
+        verifyNoInteractions(bakeService);
+
+        var status = workflow.getStatus();
+        assertThat(status.ovenReady()).isFalse();
+        assertThat(status.request()).isEqualTo(request);
+
+        workflow.ovenReady();
+        status = workflow.getStatus();
+        assertThat(status.ovenReady()).isTrue();
+        when(bakeService.bake(bakeRequest)).thenReturn(bakeResult);
+
+        // Get the workflow result
+        var result = workflow.makeCookies(request);
+
+        assertThat(result.orderId()).isEqualTo(request.orderId());
+        assertThat(result.cookies())
+                .isEqualTo(bakeResult.cookies());
+
+        var duration = Duration.ofMillis(testEnv.currentTimeMillis() - startTime);
+        assertThat(duration).isGreaterThan(Duration.ofSeconds(30));
+    }
+
+    @Test
+    void shouldNotBreakDeterminism() throws Exception {
+        var historyFile = new File("src/test/resources/history.json");
+        WorkflowReplayer.replayWorkflowExecution(historyFile, KitchenWorkflowImpl.class);
+    }
+}
diff --git a/solutions/day2/part-2.2/test/resources/history.json b/solutions/day2/part-2.2/test/resources/history.json
new file mode 100644
index 0000000..5e73fd1
--- /dev/null
+++ b/solutions/day2/part-2.2/test/resources/history.json
@@ -0,0 +1,437 @@
+{
+  "events": [
+    {
+      "eventId": "1",
+      "eventTime": "2025-05-20T09:21:02.200461472Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_STARTED",
+      "taskId": "3148028",
+      "workflowExecutionStartedEventAttributes": {
+        "workflowType": {
+          "name": "CookieOrderWorkflowV2"
+        },
+        "taskQueue": {
+          "name": "kitchen",
+          "kind": "TASK_QUEUE_KIND_NORMAL"
+        },
+        "input": {
+          "payloads": [
+            {
+              "metadata": {
+                "encoding": "anNvbi9wbGFpbg=="
+              },
+              "data": "eyJvcmRlcklkIjoiNzAyY2E1NDEtMzdiYi00YzI4LTg0NGMtZDc1OWY0ZDIyNTZjIiwicXVhbnRpdHkiOjEsImJha2luZ1ByZWZlcmVuY2UiOiJTT0ZUIiwidG9wcGluZyI6IkNIT0NPTEFURSJ9"
+            }
+          ]
+        },
+        "workflowExecutionTimeout": "0s",
+        "workflowRunTimeout": "0s",
+        "workflowTaskTimeout": "10s",
+        "originalExecutionRunId": "0196ecff-14f8-7705-af1f-58e18b61f61d",
+        "identity": "36905@MacBookPro.takima.home",
+        "firstExecutionRunId": "0196ecff-14f8-7705-af1f-58e18b61f61d",
+        "attempt": 1,
+        "firstWorkflowTaskBackoff": "0s",
+        "header": {},
+        "workflowId": "kitchen-702ca541-37bb-4c28-844c-d759f4d2256c"
+      }
+    },
+    {
+      "eventId": "2",
+      "eventTime": "2025-05-20T09:21:02.200563764Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED",
+      "taskId": "3148029",
+      "workflowTaskScheduledEventAttributes": {
+        "taskQueue": {
+          "name": "kitchen",
+          "kind": "TASK_QUEUE_KIND_NORMAL"
+        },
+        "startToCloseTimeout": "10s",
+        "attempt": 1
+      }
+    },
+    {
+      "eventId": "3",
+      "eventTime": "2025-05-20T09:21:02.209216055Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED",
+      "taskId": "3148034",
+      "workflowTaskStartedEventAttributes": {
+        "scheduledEventId": "2",
+        "identity": "36902@MacBookPro.takima.home",
+        "requestId": "e9bb9cdd-4427-4645-9cf4-07a8a2560054",
+        "historySizeBytes": "425"
+      }
+    },
+    {
+      "eventId": "4",
+      "eventTime": "2025-05-20T09:21:02.388671041Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED",
+      "taskId": "3148038",
+      "workflowTaskCompletedEventAttributes": {
+        "scheduledEventId": "2",
+        "startedEventId": "3",
+        "identity": "36902@MacBookPro.takima.home",
+        "workerVersion": {},
+        "sdkMetadata": {
+          "langUsedFlags": [
+            1
+          ]
+        },
+        "meteringMetadata": {}
+      }
+    },
+    {
+      "eventId": "5",
+      "eventTime": "2025-05-20T09:21:02.388723958Z",
+      "eventType": "EVENT_TYPE_TIMER_STARTED",
+      "taskId": "3148039",
+      "timerStartedEventAttributes": {
+        "timerId": "98d73a02-7edb-39dd-a643-79005e644b64",
+        "startToFireTimeout": "30s",
+        "workflowTaskCompletedEventId": "4"
+      }
+    },
+    {
+      "eventId": "6",
+      "eventTime": "2025-05-20T09:21:02.388758875Z",
+      "eventType": "EVENT_TYPE_ACTIVITY_TASK_SCHEDULED",
+      "taskId": "3148040",
+      "activityTaskScheduledEventAttributes": {
+        "activityId": "92159483-48ab-3725-862f-7bf8a043d767",
+        "activityType": {
+          "name": "PrepareBatter"
+        },
+        "taskQueue": {
+          "name": "batter",
+          "kind": "TASK_QUEUE_KIND_NORMAL"
+        },
+        "header": {},
+        "input": {
+          "payloads": [
+            {
+              "metadata": {
+                "encoding": "anNvbi9wbGFpbg=="
+              },
+              "data": "eyJvcmRlcklkIjoiNzAyY2E1NDEtMzdiYi00YzI4LTg0NGMtZDc1OWY0ZDIyNTZjIiwidGFyZ2V0VG9wcGluZyI6IkNIT0NPTEFURSIsInRhcmdldENvb2tpZUNvdW50IjoxfQ=="
+            }
+          ]
+        },
+        "scheduleToCloseTimeout": "0s",
+        "scheduleToStartTimeout": "0s",
+        "startToCloseTimeout": "5s",
+        "heartbeatTimeout": "0s",
+        "workflowTaskCompletedEventId": "4",
+        "retryPolicy": {
+          "initialInterval": "1s",
+          "backoffCoefficient": 2,
+          "maximumInterval": "100s",
+          "maximumAttempts": 2
+        }
+      }
+    },
+    {
+      "eventId": "7",
+      "eventTime": "2025-05-20T09:21:02.394468666Z",
+      "eventType": "EVENT_TYPE_ACTIVITY_TASK_STARTED",
+      "taskId": "3148047",
+      "activityTaskStartedEventAttributes": {
+        "scheduledEventId": "6",
+        "identity": "36781@MacBookPro.takima.home",
+        "requestId": "732e3649-f870-499a-84ef-cde1ed52afc2",
+        "attempt": 1,
+        "workerVersion": {}
+      }
+    },
+    {
+      "eventId": "8",
+      "eventTime": "2025-05-20T09:21:02.400925625Z",
+      "eventType": "EVENT_TYPE_ACTIVITY_TASK_COMPLETED",
+      "taskId": "3148048",
+      "activityTaskCompletedEventAttributes": {
+        "result": {
+          "payloads": [
+            {
+              "metadata": {
+                "encoding": "anNvbi9wbGFpbg=="
+              },
+              "data": "eyJiYXR0ZXIiOnsidG9wcGluZyI6IkNIT0NPTEFURSIsInF1YW50aXR5SW5HcmFtcyI6MzAsInRhcmdldENvb2tpZUNvdW50IjoxfX0="
+            }
+          ]
+        },
+        "scheduledEventId": "6",
+        "startedEventId": "7",
+        "identity": "36781@MacBookPro.takima.home"
+      }
+    },
+    {
+      "eventId": "9",
+      "eventTime": "2025-05-20T09:21:02.400931125Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED",
+      "taskId": "3148049",
+      "workflowTaskScheduledEventAttributes": {
+        "taskQueue": {
+          "name": "36902@MacBookPro.takima.home:27069735-1e75-4a62-9677-69417d0e5b39",
+          "kind": "TASK_QUEUE_KIND_STICKY",
+          "normalName": "kitchen"
+        },
+        "startToCloseTimeout": "10s",
+        "attempt": 1
+      }
+    },
+    {
+      "eventId": "10",
+      "eventTime": "2025-05-20T09:21:02.404223166Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED",
+      "taskId": "3148053",
+      "workflowTaskStartedEventAttributes": {
+        "scheduledEventId": "9",
+        "identity": "36902@MacBookPro.takima.home",
+        "requestId": "a1fb1d18-2dfe-4ec1-b812-3135bdf6229b",
+        "historySizeBytes": "1314"
+      }
+    },
+    {
+      "eventId": "11",
+      "eventTime": "2025-05-20T09:21:02.418556Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED",
+      "taskId": "3148057",
+      "workflowTaskCompletedEventAttributes": {
+        "scheduledEventId": "9",
+        "startedEventId": "10",
+        "identity": "36902@MacBookPro.takima.home",
+        "workerVersion": {},
+        "meteringMetadata": {}
+      }
+    },
+    {
+      "eventId": "12",
+      "eventTime": "2025-05-20T09:21:32.393183416Z",
+      "eventType": "EVENT_TYPE_TIMER_FIRED",
+      "taskId": "3148060",
+      "timerFiredEventAttributes": {
+        "timerId": "98d73a02-7edb-39dd-a643-79005e644b64",
+        "startedEventId": "5"
+      }
+    },
+    {
+      "eventId": "13",
+      "eventTime": "2025-05-20T09:21:32.393217500Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED",
+      "taskId": "3148061",
+      "workflowTaskScheduledEventAttributes": {
+        "taskQueue": {
+          "name": "36902@MacBookPro.takima.home:27069735-1e75-4a62-9677-69417d0e5b39",
+          "kind": "TASK_QUEUE_KIND_STICKY",
+          "normalName": "kitchen"
+        },
+        "startToCloseTimeout": "10s",
+        "attempt": 1
+      }
+    },
+    {
+      "eventId": "14",
+      "eventTime": "2025-05-20T09:21:32.404506541Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED",
+      "taskId": "3148065",
+      "workflowTaskStartedEventAttributes": {
+        "scheduledEventId": "13",
+        "identity": "36902@MacBookPro.takima.home",
+        "requestId": "8a083d1c-0ba7-4ca9-ae54-03e303b4d1df",
+        "historySizeBytes": "1660"
+      }
+    },
+    {
+      "eventId": "15",
+      "eventTime": "2025-05-20T09:21:32.421678958Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED",
+      "taskId": "3148069",
+      "workflowTaskCompletedEventAttributes": {
+        "scheduledEventId": "13",
+        "startedEventId": "14",
+        "identity": "36902@MacBookPro.takima.home",
+        "workerVersion": {},
+        "meteringMetadata": {}
+      }
+    },
+    {
+      "eventId": "16",
+      "eventTime": "2025-05-20T09:31:25.471000502Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED",
+      "taskId": "3148071",
+      "workflowExecutionSignaledEventAttributes": {
+        "signalName": "ovenReady",
+        "input": {}
+      }
+    },
+    {
+      "eventId": "17",
+      "eventTime": "2025-05-20T09:31:25.471008835Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED",
+      "taskId": "3148072",
+      "workflowTaskScheduledEventAttributes": {
+        "taskQueue": {
+          "name": "36902@MacBookPro.takima.home:27069735-1e75-4a62-9677-69417d0e5b39",
+          "kind": "TASK_QUEUE_KIND_STICKY",
+          "normalName": "kitchen"
+        },
+        "startToCloseTimeout": "10s",
+        "attempt": 1
+      }
+    },
+    {
+      "eventId": "18",
+      "eventTime": "2025-05-20T09:31:25.478133502Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED",
+      "taskId": "3148076",
+      "workflowTaskStartedEventAttributes": {
+        "scheduledEventId": "17",
+        "identity": "36902@MacBookPro.takima.home",
+        "requestId": "14720a8e-9b34-419c-a8a9-559b40c19f8c",
+        "historySizeBytes": "1979"
+      }
+    },
+    {
+      "eventId": "19",
+      "eventTime": "2025-05-20T09:31:25.494807919Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED",
+      "taskId": "3148080",
+      "workflowTaskCompletedEventAttributes": {
+        "scheduledEventId": "17",
+        "startedEventId": "18",
+        "identity": "36902@MacBookPro.takima.home",
+        "workerVersion": {},
+        "meteringMetadata": {}
+      }
+    },
+    {
+      "eventId": "20",
+      "eventTime": "2025-05-20T09:31:25.494843794Z",
+      "eventType": "EVENT_TYPE_ACTIVITY_TASK_SCHEDULED",
+      "taskId": "3148081",
+      "activityTaskScheduledEventAttributes": {
+        "activityId": "23d7c2c4-cb8c-3dee-b3d2-e8300ca29511",
+        "activityType": {
+          "name": "Bake"
+        },
+        "taskQueue": {
+          "name": "bake",
+          "kind": "TASK_QUEUE_KIND_NORMAL"
+        },
+        "header": {},
+        "input": {
+          "payloads": [
+            {
+              "metadata": {
+                "encoding": "anNvbi9wbGFpbg=="
+              },
+              "data": "eyJvcmRlcklkIjoiNzAyY2E1NDEtMzdiYi00YzI4LTg0NGMtZDc1OWY0ZDIyNTZjIiwiYmF0dGVyIjp7InRvcHBpbmciOiJDSE9DT0xBVEUiLCJxdWFudGl0eUluR3JhbXMiOjMwLCJ0YXJnZXRDb29raWVDb3VudCI6MX0sImJha2luZ1ByZWZlcmVuY2UiOiJTT0ZUIn0="
+            }
+          ]
+        },
+        "scheduleToCloseTimeout": "0s",
+        "scheduleToStartTimeout": "0s",
+        "startToCloseTimeout": "5s",
+        "heartbeatTimeout": "0s",
+        "workflowTaskCompletedEventId": "19",
+        "retryPolicy": {
+          "initialInterval": "1s",
+          "backoffCoefficient": 2,
+          "maximumInterval": "100s",
+          "maximumAttempts": 2
+        }
+      }
+    },
+    {
+      "eventId": "21",
+      "eventTime": "2025-05-20T09:31:25.498424877Z",
+      "eventType": "EVENT_TYPE_ACTIVITY_TASK_STARTED",
+      "taskId": "3148086",
+      "activityTaskStartedEventAttributes": {
+        "scheduledEventId": "20",
+        "identity": "36783@MacBookPro.takima.home",
+        "requestId": "31445516-84c7-4cb3-8d81-95c62fba17a3",
+        "attempt": 1,
+        "workerVersion": {}
+      }
+    },
+    {
+      "eventId": "22",
+      "eventTime": "2025-05-20T09:31:25.582749377Z",
+      "eventType": "EVENT_TYPE_ACTIVITY_TASK_COMPLETED",
+      "taskId": "3148087",
+      "activityTaskCompletedEventAttributes": {
+        "result": {
+          "payloads": [
+            {
+              "metadata": {
+                "encoding": "anNvbi9wbGFpbg=="
+              },
+              "data": "eyJjb29raWVzIjpbeyJiYWtpbmdQcmVmZXJlbmNlIjoiU09GVCIsInRvcHBpbmciOiJDSE9DT0xBVEUifV19"
+            }
+          ]
+        },
+        "scheduledEventId": "20",
+        "startedEventId": "21",
+        "identity": "36783@MacBookPro.takima.home"
+      }
+    },
+    {
+      "eventId": "23",
+      "eventTime": "2025-05-20T09:31:25.582760710Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_SCHEDULED",
+      "taskId": "3148088",
+      "workflowTaskScheduledEventAttributes": {
+        "taskQueue": {
+          "name": "36902@MacBookPro.takima.home:27069735-1e75-4a62-9677-69417d0e5b39",
+          "kind": "TASK_QUEUE_KIND_STICKY",
+          "normalName": "kitchen"
+        },
+        "startToCloseTimeout": "10s",
+        "attempt": 1
+      }
+    },
+    {
+      "eventId": "24",
+      "eventTime": "2025-05-20T09:31:25.589439919Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_STARTED",
+      "taskId": "3148092",
+      "workflowTaskStartedEventAttributes": {
+        "scheduledEventId": "23",
+        "identity": "36902@MacBookPro.takima.home",
+        "requestId": "e6cd5cd1-4f48-4d44-86b3-de2543e020c3",
+        "historySizeBytes": "2820"
+      }
+    },
+    {
+      "eventId": "25",
+      "eventTime": "2025-05-20T09:31:25.603636960Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_TASK_COMPLETED",
+      "taskId": "3148096",
+      "workflowTaskCompletedEventAttributes": {
+        "scheduledEventId": "23",
+        "startedEventId": "24",
+        "identity": "36902@MacBookPro.takima.home",
+        "workerVersion": {},
+        "meteringMetadata": {}
+      }
+    },
+    {
+      "eventId": "26",
+      "eventTime": "2025-05-20T09:31:25.603693210Z",
+      "eventType": "EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED",
+      "taskId": "3148097",
+      "workflowExecutionCompletedEventAttributes": {
+        "result": {
+          "payloads": [
+            {
+              "metadata": {
+                "encoding": "anNvbi9wbGFpbg=="
+              },
+              "data": "eyJvcmRlcklkIjoiNzAyY2E1NDEtMzdiYi00YzI4LTg0NGMtZDc1OWY0ZDIyNTZjIiwiY29va2llcyI6W3siYmFraW5nUHJlZmVyZW5jZSI6IlNPRlQiLCJ0b3BwaW5nIjoiQ0hPQ09MQVRFIn1dfQ=="
+            }
+          ]
+        },
+        "workflowTaskCompletedEventId": "25"
+      }
+    }
+  ]
+}
\ No newline at end of file
-- 
GitLab