diff --git a/workflows/multiapp/E-CommerceArchitecture.png b/workflows/multiapp/E-CommerceArchitecture.png
new file mode 100644
index 000000000..b798e908c
Binary files /dev/null and b/workflows/multiapp/E-CommerceArchitecture.png differ
diff --git a/workflows/multiapp/README.md b/workflows/multiapp/README.md
new file mode 100644
index 000000000..edd822d1c
--- /dev/null
+++ b/workflows/multiapp/README.md
@@ -0,0 +1,117 @@
+# Multi-App E-commerce Workflow Demo
+
+This demo showcases a realistic e-commerce order processing scenario using Dapr's multi-application workflow capabilities. The scenario demonstrates how a Go application can orchestrate complex business processes across multiple Java services, including AI-powered recommendations.
+
+## Architecture
+
+
+
+The demo consists of four applications working together:
+
+1. **Go Order Orchestrator** - Main workflow coordinator
+2. **Java Payment Service** - Payment processing
+3. **Java Inventory Service** - Inventory management and reservation
+4. **Java AI Recommendation Service** - AI-powered product recommendations
+
+## Prerequisites
+
+- Dapr CLI installed and initialized (`dapr init`)
+- Go installed
+- Java and Maven installed
+
+## Quick Start
+
+### 1. Build All Services
+
+```bash
+make build
+```
+
+### 2. Run All Services
+
+#### Option A: Run with Multi-App Configuration (Recommended)
+
+```bash
+dapr run -f dapr.yaml
+```
+
+#### Option B: Run in Separate Terminals
+
+**Terminal 1 - Go Order Orchestrator:**
+```bash
+make run-go
+```
+
+**Terminal 2 - Java Payment Service:**
+```bash
+make run-payment
+```
+
+**Terminal 3 - Java Inventory Service:**
+```bash
+make run-inventory
+```
+
+**Terminal 4 - Java AI Recommendation Service:**
+```bash
+make run-ai
+```
+
+### 3. Test the Workflow
+
+Send a POST request to start the workflow:
+
+```bash
+curl -X POST http://localhost:50001/start-workflow
+```
+
+## Service Ports
+
+- **Go Order Orchestrator**: 50001 (Dapr HTTP: 3505)
+- **Java Payment Service**: 50002 (Dapr HTTP: 3506)
+- **Java Inventory Service**: 50003 (Dapr HTTP: 3507)
+- **Java AI Recommendation Service**: 50004 (Dapr HTTP: 3508)
+
+## Development
+
+### Building Individual Services
+
+```bash
+# Go Order Orchestrator
+cd go/order-orchestrator
+go mod tidy
+go run .
+
+# Java Payment Service
+cd java/payment-service
+mvn clean package
+java -jar target/payment-service-1.0.0.jar
+
+# Java Inventory Service
+cd java/inventory-service
+mvn clean package
+java -jar target/inventory-service-1.0.0.jar
+
+# Java AI Recommendation Service
+cd java/ai-recommendation-service
+mvn clean package
+java -jar target/ai-recommendation-service-1.0.0.jar
+```
+
+### Testing
+
+```bash
+make test
+```
+
+### Cleanup
+
+```bash
+make clean
+```
+
+## Related Resources
+
+- [Multi-Application Workflows Documentation](https://docs.dapr.io/developing-applications/building-blocks/workflow/workflow-multi-app/)
+- [Multi-Application Java Workflows Example](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/workflows/multiapp)
+- [Multi-Application Spring Boot Workflows Example](https://github.com/dapr/java-sdk/tree/master/spring-boot-examples/workflows/multi-app)
diff --git a/workflows/multiapp/components/statestore.yaml b/workflows/multiapp/components/statestore.yaml
new file mode 100644
index 000000000..02561e72f
--- /dev/null
+++ b/workflows/multiapp/components/statestore.yaml
@@ -0,0 +1,16 @@
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: statestore
+spec:
+ type: state.redis
+ version: v1
+ metadata:
+ - name: redisHost
+ value: localhost:6379
+ - name: redisPassword
+ value: ""
+ - name: enableTLS
+ value: false
+ - name: actorStateStore
+ value: "true"
diff --git a/workflows/multiapp/dapr.yaml b/workflows/multiapp/dapr.yaml
new file mode 100644
index 000000000..b33d24198
--- /dev/null
+++ b/workflows/multiapp/dapr.yaml
@@ -0,0 +1,28 @@
+version: 1
+common:
+ resourcesPath: ./components
+apps:
+ - appID: order-orchestrator
+ appDirPath: ./go/order-orchestrator/
+ appPort: 50001
+ daprHTTPPort: 3505
+ daprGRPCPort: 50014
+ command: ["go", "run", "."]
+ - appID: payment-service
+ appDirPath: ./java/payment-service/
+ appPort: 50002
+ daprHTTPPort: 3506
+ daprGRPCPort: 50015
+ command: ["java", "-jar", "target/payment-service-1.0.0.jar"]
+ - appID: inventory-service
+ appDirPath: ./java/inventory-service/
+ appPort: 50003
+ daprHTTPPort: 3507
+ daprGRPCPort: 50016
+ command: ["java", "-jar", "target/inventory-service-1.0.0.jar"]
+ - appID: ai-recommendation-service
+ appDirPath: ./java/ai-recommendation-service/
+ appPort: 50004
+ daprHTTPPort: 3508
+ daprGRPCPort: 50017
+ command: ["java", "-jar", "target/ai-recommendation-service-1.0.0.jar"]
diff --git a/workflows/multiapp/go/order-orchestrator/go.mod b/workflows/multiapp/go/order-orchestrator/go.mod
new file mode 100644
index 000000000..bab765c75
--- /dev/null
+++ b/workflows/multiapp/go/order-orchestrator/go.mod
@@ -0,0 +1,30 @@
+module order-orchestrator
+
+go 1.24.6
+
+toolchain go1.24.7
+
+require (
+ github.com/dapr/durabletask-go v0.10.0
+ github.com/dapr/go-sdk v1.13.0
+)
+
+require (
+ github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+ github.com/dapr/dapr v1.16.0 // indirect
+ github.com/dapr/kit v0.16.1 // indirect
+ github.com/go-logr/logr v1.4.2 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+ go.opentelemetry.io/otel v1.36.0 // indirect
+ go.opentelemetry.io/otel/metric v1.36.0 // indirect
+ go.opentelemetry.io/otel/trace v1.36.0 // indirect
+ golang.org/x/net v0.41.0 // indirect
+ golang.org/x/sys v0.33.0 // indirect
+ golang.org/x/text v0.26.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
+ google.golang.org/grpc v1.73.0 // indirect
+ google.golang.org/protobuf v1.36.6 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/workflows/multiapp/go/order-orchestrator/go.sum b/workflows/multiapp/go/order-orchestrator/go.sum
new file mode 100644
index 000000000..6fd6362ab
--- /dev/null
+++ b/workflows/multiapp/go/order-orchestrator/go.sum
@@ -0,0 +1,62 @@
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/dapr/dapr v1.16.0 h1:la2WLZM8Myr2Pq3cyrFjHKWDSPYLzGZCs3p502TwBjI=
+github.com/dapr/dapr v1.16.0/go.mod h1:ln/mxvNOeqklaDmic4ppsxmnjl2D/oZGKaJy24IwaEY=
+github.com/dapr/durabletask-go v0.10.0 h1:vfIivPl4JYd55xZTslDwhA6p6F8ipcNxBtMaupxArr8=
+github.com/dapr/durabletask-go v0.10.0/go.mod h1:0Ts4rXp74JyG19gDWPcwNo5V6NBZzhARzHF5XynmA7Q=
+github.com/dapr/go-sdk v1.13.0 h1:Qw2BmUonClQ9yK/rrEEaFL1PyDgq616RrvYj0CT67Lk=
+github.com/dapr/go-sdk v1.13.0/go.mod h1:RsffVNZitDApmQqoS68tNKGMXDZUjTviAbKZupJSzts=
+github.com/dapr/kit v0.16.1 h1:MqLAhHVg8trPy2WJChMZFU7ToeondvxcNHYVvMDiVf4=
+github.com/dapr/kit v0.16.1/go.mod h1:40ZWs5P6xfYf7O59XgwqZkIyDldTIXlhTQhGop8QoSM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
+go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
+go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
+go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
+go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
+go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
+go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
+go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
+go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
+go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
+go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
+go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
+golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
+golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
+golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
+google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
+google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
+google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/workflows/multiapp/go/order-orchestrator/main.go b/workflows/multiapp/go/order-orchestrator/main.go
new file mode 100644
index 000000000..a3604dea3
--- /dev/null
+++ b/workflows/multiapp/go/order-orchestrator/main.go
@@ -0,0 +1,218 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "net/http"
+ "time"
+
+ "github.com/dapr/durabletask-go/workflow"
+ "github.com/dapr/go-sdk/client"
+)
+
+func main() {
+ // Create a workflow registry
+ registry := workflow.NewRegistry()
+
+ // Register the workflow
+ registry.AddWorkflow(OrderProcessingWorkflow)
+
+ log.Println("OrderProcessingWorkflow registered")
+
+ // Register local activities
+ registry.AddActivity(ValidateOrderActivity)
+ registry.AddActivity(CompleteOrderActivity)
+
+ log.Println("ValidateOrderActivity registered")
+ log.Println("CompleteOrderActivity registered")
+
+ // Create a workflow client using the new vanity client
+ wclient, err := client.NewWorkflowClient()
+ if err != nil {
+ log.Fatalf("Failed to create workflow client: %v", err)
+ }
+ log.Println("Workflow client initialized")
+
+ // Start the workflow worker
+ ctx := context.Background()
+ if err := wclient.StartWorker(ctx, registry); err != nil {
+ log.Fatalf("Failed to start workflow worker: %v", err)
+ }
+ log.Println("Workflow worker started")
+
+ // Start HTTP server for health checks and workflow triggering
+ http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte("Order Orchestrator is running"))
+ })
+
+ http.HandleFunc("/start-workflow", func(w http.ResponseWriter, r *http.Request) {
+ log.Println("Starting workflow execution via HTTP endpoint...")
+
+ // Create a sample order
+ order := OrderRequest{
+ OrderID: "ORDER-001",
+ CustomerID: "CUST-001",
+ Items: []Item{
+ {ProductID: "PROD-001", Name: "Laptop", Price: 999.99, Quantity: 1},
+ {ProductID: "PROD-002", Name: "Mouse", Price: 29.99, Quantity: 2},
+ },
+ PaymentMethod: "credit_card",
+ }
+ // Calculate the total from items
+ order.CalculateTotal()
+
+ log.Printf("Scheduling workflow with input: %+v", order)
+ instanceID := fmt.Sprintf("ORDER-%d", time.Now().Unix())
+ _, err := wclient.ScheduleWorkflow(ctx, "OrderProcessingWorkflow",
+ workflow.WithInstanceID(instanceID),
+ workflow.WithInput(order))
+ if err != nil {
+ log.Printf("Failed to start workflow: %v", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte(fmt.Sprintf("Failed to start workflow: %v", err)))
+ return
+ }
+
+ log.Printf("Workflow scheduled successfully with instance ID: %s", instanceID)
+
+ log.Println("Waiting for workflow completion...")
+ waitCtx, waitCancel := context.WithTimeout(context.Background(), 60*time.Second)
+ result, err := wclient.WaitForWorkflowCompletion(waitCtx, instanceID)
+ waitCancel()
+ if err != nil {
+ log.Printf("Failed to wait for workflow completion: %v", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Write([]byte(fmt.Sprintf("Failed to wait for workflow completion: %v", err)))
+ } else {
+ log.Printf("Workflow completed successfully with result: %+v", result)
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte(fmt.Sprintf("Workflow completed successfully: %+v", result)))
+ }
+ })
+
+ log.Println("Starting HTTP server on port 50001...")
+ log.Fatal(http.ListenAndServe(":50001", nil))
+}
+
+// OrderProcessingWorkflow orchestrates the entire order processing workflow
+func OrderProcessingWorkflow(ctx *workflow.WorkflowContext) (any, error) {
+ log.Println("=== OrderProcessingWorkflow STARTED ===")
+
+ var input OrderRequest
+ if err := ctx.GetInput(&input); err != nil {
+ return nil, fmt.Errorf("failed to get workflow input: %w", err)
+ }
+ log.Printf("Processing order: %s for customer: %s", input.OrderID, input.CustomerID)
+ log.Printf("Full input: %+v", input)
+
+ // Step 1: Validate Order (local activity)
+ var validationResult OrderValidationResult
+ if err := ctx.CallActivity("ValidateOrderActivity",
+ workflow.WithActivityInput(input)).Await(&validationResult); err != nil {
+ return nil, fmt.Errorf("order validation failed: %w", err)
+ }
+
+ // Step 2: Process Payment (call Java payment service)
+ log.Println("=== STEP 2: Starting Payment Processing activity on payment-service ===")
+ var paymentResult string
+ if err := ctx.CallActivity("io.dapr.quickstarts.workflows.activities.ValidatePaymentMethodActivity",
+ workflow.WithActivityInput(input),
+ workflow.WithActivityAppID("payment-service")).Await(&paymentResult); err != nil {
+ log.Printf("ERROR: Payment processing failed with error: %v", err)
+ return nil, fmt.Errorf("payment processing failed: %w", err)
+ }
+ log.Println("=== STEP 2: Payment Processing COMPLETED ===")
+
+ // Step 3: Reserve Inventory (call inventory-service)
+ log.Println("=== STEP 3: Starting Inventory Reservation activity on inventory-service ===")
+ var inventoryResult InventoryResult
+ if err := ctx.CallActivity("io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity",
+ workflow.WithActivityInput(input),
+ workflow.WithActivityAppID("inventory-service")).Await(&inventoryResult); err != nil {
+ log.Printf("ERROR: Inventory reservation failed with error: %v", err)
+ return nil, fmt.Errorf("inventory reservation failed: %w", err)
+ }
+ log.Println("=== STEP 3: Inventory Reservation COMPLETED ===")
+
+ // Step 4: Generate AI Recommendations (call AI recommendation service)
+ log.Println("=== STEP 4: Starting AI Recommendations activity on ai-recommendation-service ===")
+ var recommendationResult RecommendationResult
+ if err := ctx.CallActivity("io.dapr.quickstarts.workflows.activities.GeneratePersonalizedRecommendationsActivity",
+ workflow.WithActivityInput(input),
+ workflow.WithActivityAppID("ai-recommendation-service")).Await(&recommendationResult); err != nil {
+ log.Printf("ERROR: AI recommendations failed with error: %v", err)
+ return nil, fmt.Errorf("AI recommendations failed: %w", err)
+ }
+ log.Println("=== STEP 4: AI Recommendations COMPLETED ===")
+
+ // Step 5: Complete Order (local activity)
+ log.Println("=== STEP 5: Starting Order Completion activity (local) ===")
+ var orderResult OrderResult
+ if err := ctx.CallActivity("CompleteOrderActivity", workflow.WithActivityInput(input)).Await(&orderResult); err != nil {
+ log.Printf("ERROR: Order completion failed with error: %v", err)
+ return nil, fmt.Errorf("order completion failed: %w", err)
+ }
+ log.Println("=== STEP 5: Order Completion COMPLETED ===")
+
+ // Create final result with all working steps
+ finalResult := map[string]interface{}{
+ "validation": validationResult,
+ "payment": paymentResult,
+ "inventory": inventoryResult,
+ "recommendations": recommendationResult,
+ "order": orderResult,
+ }
+
+ log.Println("=== OrderProcessingWorkflow COMPLETED SUCCESSFULLY ===")
+ return finalResult, nil
+}
+
+// ValidateOrderActivity validates the order locally
+func ValidateOrderActivity(ctx workflow.ActivityContext) (any, error) {
+ log.Println("=== ValidateOrderActivity (local) STARTED ===")
+
+ var input OrderRequest
+ if err := ctx.GetInput(&input); err != nil {
+ return nil, fmt.Errorf("failed to get activity input: %w", err)
+ }
+ log.Printf("Validating order: %s", input.OrderID)
+
+ // Simulate validation logic
+ time.Sleep(1 * time.Second)
+
+ result := OrderValidationResult{
+ Valid: true,
+ Total: input.Total,
+ Message: "Order validation successful",
+ }
+
+ log.Println("=== ValidateOrderActivity (local) COMPLETED ===")
+ return result, nil
+}
+
+// CompleteOrderActivity completes the order locally
+func CompleteOrderActivity(ctx workflow.ActivityContext) (any, error) {
+ log.Println("=== CompleteOrderActivity (local) STARTED ===")
+
+ var input OrderRequest
+ if err := ctx.GetInput(&input); err != nil {
+ return nil, fmt.Errorf("failed to get activity input: %w", err)
+ }
+ log.Printf("Completing order: %s", input.OrderID)
+
+ // Simulate order completion logic
+ time.Sleep(1 * time.Second)
+
+ result := OrderResult{
+ OrderID: input.OrderID,
+ CustomerID: input.CustomerID,
+ Status: "completed",
+ Total: input.Total,
+ Message: "Order completed successfully",
+ }
+
+ log.Println("=== CompleteOrderActivity (local) COMPLETED ===")
+ return result, nil
+}
diff --git a/workflows/multiapp/go/order-orchestrator/models.go b/workflows/multiapp/go/order-orchestrator/models.go
new file mode 100644
index 000000000..215102650
--- /dev/null
+++ b/workflows/multiapp/go/order-orchestrator/models.go
@@ -0,0 +1,66 @@
+package main
+
+// OrderRequest represents an incoming order
+type OrderRequest struct {
+ OrderID string `json:"orderId"`
+ CustomerID string `json:"customerId"`
+ Items []Item `json:"items"`
+ PaymentMethod string `json:"paymentMethod"`
+ Total float64 `json:"total"`
+}
+
+// CalculateTotal calculates the total price for all items in the order
+func (o *OrderRequest) CalculateTotal() float64 {
+ total := 0.0
+ for _, item := range o.Items {
+ total += item.Price * float64(item.Quantity)
+ }
+ o.Total = total
+ return total
+}
+
+// Item represents a product in an order
+type Item struct {
+ ProductID string `json:"productId"`
+ Name string `json:"name"`
+ Price float64 `json:"price"`
+ Quantity int `json:"quantity"`
+}
+
+// OrderValidationResult represents the result of order validation
+type OrderValidationResult struct {
+ Valid bool `json:"valid"`
+ Total float64 `json:"total"`
+ Message string `json:"message"`
+}
+
+// InventoryResult represents the result of inventory reservation
+type InventoryResult struct {
+ Success bool `json:"success"`
+ ReservedItems []Item `json:"reservedItems"`
+ Message string `json:"message"`
+}
+
+// RecommendedItem represents a recommended product
+type RecommendedItem struct {
+ ProductID string `json:"productId"`
+ Name string `json:"name"`
+ Price float64 `json:"price"`
+ Reason string `json:"reason"`
+}
+
+// RecommendationResult represents the result of AI recommendations
+type RecommendationResult struct {
+ Success bool `json:"success"`
+ Recommendations []RecommendedItem `json:"recommendations"`
+ Message string `json:"message"`
+}
+
+// OrderResult represents the final result of order processing
+type OrderResult struct {
+ OrderID string `json:"orderId"`
+ CustomerID string `json:"customerId"`
+ Status string `json:"status"`
+ Total float64 `json:"total"`
+ Message string `json:"message"`
+}
diff --git a/workflows/multiapp/java/.sdkmanrc b/workflows/multiapp/java/.sdkmanrc
new file mode 100644
index 000000000..543d268ab
--- /dev/null
+++ b/workflows/multiapp/java/.sdkmanrc
@@ -0,0 +1,4 @@
+# Enable auto-env through the sdkman_auto_env config
+# Add key=value pairs of SDKs to use below
+java=17.0.11-tem
+maven=3.8.5
\ No newline at end of file
diff --git a/workflows/multiapp/java/ai-recommendation-service/pom.xml b/workflows/multiapp/java/ai-recommendation-service/pom.xml
new file mode 100644
index 000000000..2c773818e
--- /dev/null
+++ b/workflows/multiapp/java/ai-recommendation-service/pom.xml
@@ -0,0 +1,75 @@
+
+
+ 4.0.0
+
+ io.dapr.quickstarts
+ ai-recommendation-service
+ 1.0.0
+ jar
+
+ AI Recommendation Service
+ Java AI Recommendation Service for Multi-App Workflows
+
+
+ 17
+ 17
+ UTF-8
+ 1.16.0
+
+
+
+
+
+ io.dapr
+ dapr-sdk-workflows
+ ${dapr.sdk.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 17
+ 17
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.4.1
+
+
+ package
+
+ shade
+
+
+
+
+ io.dapr.quickstarts.workflows.AIRecommendationServiceApplication
+
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows/multiapp/java/ai-recommendation-service/src/main/java/io/dapr/quickstarts/workflows/AIRecommendationServiceApplication.java b/workflows/multiapp/java/ai-recommendation-service/src/main/java/io/dapr/quickstarts/workflows/AIRecommendationServiceApplication.java
new file mode 100644
index 000000000..dd8c99ea6
--- /dev/null
+++ b/workflows/multiapp/java/ai-recommendation-service/src/main/java/io/dapr/quickstarts/workflows/AIRecommendationServiceApplication.java
@@ -0,0 +1,51 @@
+package io.dapr.quickstarts.workflows;
+
+import io.dapr.workflows.runtime.WorkflowRuntime;
+import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
+import io.dapr.quickstarts.workflows.activities.GeneratePersonalizedRecommendationsActivity;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpExchange;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+
+/**
+ * AIRecommendationServiceWorker - registers only the GeneratePersonalizedRecommendationsActivity.
+ * This activity is called multi-app from the main workflow (written in Go).
+ */
+public class AIRecommendationServiceApplication {
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("=== Starting AIRecommendationServiceWorker (GeneratePersonalizedRecommendationsActivity) ===");
+
+ // Start HTTP server on port 50004
+ HttpServer server = HttpServer.create(new InetSocketAddress(50004), 0);
+ server.createContext("/health", new HealthHandler());
+ server.setExecutor(null);
+ server.start();
+ System.out.println("HTTP server started on port 50004");
+
+ WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder()
+ .registerActivity(GeneratePersonalizedRecommendationsActivity.class);
+
+ // Build and start the workflow runtime
+ try (WorkflowRuntime runtime = builder.build()) {
+ System.out.println("AIRecommendationServiceWorker started - registered GeneratePersonalizedRecommendationsActivity only");
+ System.out.println("AI Recommendation Service is ready to receive multi-app activity calls...");
+ System.out.println("Waiting for multi-app activity calls...");
+ runtime.start();
+ }
+ }
+
+ static class HealthHandler implements HttpHandler {
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ String response = "AI Recommendation Service is running";
+ exchange.sendResponseHeaders(200, response.length());
+ OutputStream os = exchange.getResponseBody();
+ os.write(response.getBytes());
+ os.close();
+ }
+ }
+}
diff --git a/workflows/multiapp/java/ai-recommendation-service/src/main/java/io/dapr/quickstarts/workflows/activities/GeneratePersonalizedRecommendationsActivity.java b/workflows/multiapp/java/ai-recommendation-service/src/main/java/io/dapr/quickstarts/workflows/activities/GeneratePersonalizedRecommendationsActivity.java
new file mode 100644
index 000000000..1a636627c
--- /dev/null
+++ b/workflows/multiapp/java/ai-recommendation-service/src/main/java/io/dapr/quickstarts/workflows/activities/GeneratePersonalizedRecommendationsActivity.java
@@ -0,0 +1,66 @@
+package io.dapr.quickstarts.workflows.activities;
+
+import io.dapr.workflows.WorkflowActivity;
+import io.dapr.workflows.WorkflowActivityContext;
+
+/**
+ * GeneratePersonalizedRecommendationsActivity for AI Recommendation Service - generates AI recommendations.
+ * This activity is called cross-app from the main workflow.
+ */
+public class GeneratePersonalizedRecommendationsActivity implements WorkflowActivity {
+ @Override
+ public Object run(WorkflowActivityContext context) {
+ var logger = context.getLogger();
+ logger.info("=== AI Recommendation Service: GeneratePersonalizedRecommendationsActivity STARTED ===");
+
+ try {
+ Object inputObj = context.getInput(Object.class);
+ logger.info("Received order: {}", inputObj);
+
+ // Create RecommendationResult object
+ RecommendationResult result = new RecommendationResult();
+ result.success = true;
+ result.recommendations = new RecommendedItem[]{
+ new RecommendedItem("PROD-003", "Wireless Headphones", 99.99, "Based on your laptop purchase"),
+ new RecommendedItem("PROD-004", "USB-C Hub", 49.99, "Complements your laptop setup")
+ };
+ result.message = "AI recommendations generated successfully by AI recommendation service";
+ logger.info("=== AI Recommendation Service: GeneratePersonalizedRecommendationsActivity COMPLETED SUCCESSFULLY ===");
+
+ return result;
+ } catch (Exception e) {
+ logger.error("ERROR in GeneratePersonalizedRecommendationsActivity: {}", e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ // RecommendationResult class (to match Go struct)
+ public static class RecommendationResult {
+ public boolean success;
+ public RecommendedItem[] recommendations;
+ public String message;
+
+ @Override
+ public String toString() {
+ return String.format("RecommendationResult{success=%s, recommendations=%d items, message='%s'}",
+ success, recommendations != null ? recommendations.length : 0, message);
+ }
+ }
+
+ // RecommendedItem class (to match Go struct)
+ public static class RecommendedItem {
+ public String productId;
+ public String name;
+ public double price;
+ public String reason;
+
+ public RecommendedItem() {}
+
+ public RecommendedItem(String productId, String name, double price, String reason) {
+ this.productId = productId;
+ this.name = name;
+ this.price = price;
+ this.reason = reason;
+ }
+ }
+}
diff --git a/workflows/multiapp/java/inventory-service/pom.xml b/workflows/multiapp/java/inventory-service/pom.xml
new file mode 100644
index 000000000..bf5401831
--- /dev/null
+++ b/workflows/multiapp/java/inventory-service/pom.xml
@@ -0,0 +1,75 @@
+
+
+ 4.0.0
+
+ io.dapr.quickstarts
+ inventory-service
+ 1.0.0
+ jar
+
+ Inventory Service
+ Java Inventory Service for Multi-App Workflows
+
+
+ 17
+ 17
+ UTF-8
+ 1.16.0
+
+
+
+
+
+ io.dapr
+ dapr-sdk-workflows
+ ${dapr.sdk.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 17
+ 17
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.4.1
+
+
+ package
+
+ shade
+
+
+
+
+ io.dapr.quickstarts.workflows.InventoryServiceApplication
+
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/workflows/multiapp/java/inventory-service/src/main/java/io/dapr/quickstarts/workflows/InventoryServiceApplication.java b/workflows/multiapp/java/inventory-service/src/main/java/io/dapr/quickstarts/workflows/InventoryServiceApplication.java
new file mode 100644
index 000000000..80a5056ff
--- /dev/null
+++ b/workflows/multiapp/java/inventory-service/src/main/java/io/dapr/quickstarts/workflows/InventoryServiceApplication.java
@@ -0,0 +1,52 @@
+package io.dapr.quickstarts.workflows;
+
+import io.dapr.workflows.runtime.WorkflowRuntime;
+import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
+import io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpExchange;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+
+/**
+ * InventoryServiceWorker - registers only the ReserveInventoryActivity.
+ * This app will handle multi-app activity calls from the main workflow.
+ */
+public class InventoryServiceApplication {
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("=== Starting InventoryServiceWorker (ReserveInventoryActivity) ===");
+
+ // Start HTTP server on port 50003
+ HttpServer server = HttpServer.create(new InetSocketAddress(50003), 0);
+ server.createContext("/health", new HealthHandler());
+ server.setExecutor(null);
+ server.start();
+ System.out.println("HTTP server started on port 50003");
+
+ WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder()
+ .registerActivity(ReserveInventoryActivity.class);
+
+ // Build and start the workflow runtime
+ try (WorkflowRuntime runtime = builder.build()) {
+ System.out.println("InventoryServiceWorker started - registered ReserveInventoryActivity only");
+ System.out.println("Inventory Service is ready to receive cross-app activity calls...");
+ System.out.println("Waiting for cross-app activity calls...");
+ runtime.start();
+ }
+ }
+
+ static class HealthHandler implements HttpHandler {
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ String response = "Inventory Service is running";
+ exchange.sendResponseHeaders(200, response.length());
+ OutputStream os = exchange.getResponseBody();
+ os.write(response.getBytes());
+ os.close();
+ }
+ }
+
+}
diff --git a/workflows/multiapp/java/inventory-service/src/main/java/io/dapr/quickstarts/workflows/activities/ReserveInventoryActivity.java b/workflows/multiapp/java/inventory-service/src/main/java/io/dapr/quickstarts/workflows/activities/ReserveInventoryActivity.java
new file mode 100644
index 000000000..676d6305e
--- /dev/null
+++ b/workflows/multiapp/java/inventory-service/src/main/java/io/dapr/quickstarts/workflows/activities/ReserveInventoryActivity.java
@@ -0,0 +1,54 @@
+package io.dapr.quickstarts.workflows.activities;
+
+import io.dapr.workflows.WorkflowActivity;
+import io.dapr.workflows.WorkflowActivityContext;
+
+/**
+ * ReserveInventoryActivity for Inventory Service - reserves inventory items.
+ * This activity is called multi-app from the main workflow.
+ */
+public class ReserveInventoryActivity implements WorkflowActivity {
+ @Override
+ public Object run(WorkflowActivityContext context) {
+ var logger = context.getLogger();
+ logger.info("=== Inventory Service: ReserveInventoryActivity STARTED ===");
+
+ try {
+ Object inputObj = context.getInput(Object.class);
+ logger.info("Received order: {}", inputObj);
+
+ // Create InventoryResult object
+ InventoryResult result = new InventoryResult();
+ result.success = true;
+ result.reservedItems = new Item[0];
+ result.message = "Inventory reserved successfully by inventory service";
+ logger.info("=== Inventory Service: ReserveInventoryActivity COMPLETED SUCCESSFULLY ===");
+
+ return result;
+ } catch (Exception e) {
+ logger.error("ERROR in ReserveInventoryActivity: {}", e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ // InventoryResult class (to match Go struct)
+ public static class InventoryResult {
+ public boolean success;
+ public Item[] reservedItems;
+ public String message;
+
+ @Override
+ public String toString() {
+ return String.format("InventoryResult{success=%s, reservedItems=%d items, message='%s'}",
+ success, reservedItems != null ? reservedItems.length : 0, message);
+ }
+ }
+
+ // Item class (to match Go struct)
+ public static class Item {
+ public String productId;
+ public String name;
+ public double price;
+ public int quantity;
+ }
+}
diff --git a/workflows/multiapp/java/payment-service/pom.xml b/workflows/multiapp/java/payment-service/pom.xml
new file mode 100644
index 000000000..ea9e880b5
--- /dev/null
+++ b/workflows/multiapp/java/payment-service/pom.xml
@@ -0,0 +1,75 @@
+
+
+ 4.0.0
+
+ io.dapr.quickstarts
+ payment-service
+ 1.0.0
+ jar
+
+ Payment Service
+ Java Payment Service for Multi-App Workflows
+
+
+ 17
+ 17
+ UTF-8
+ 1.16.0
+
+
+
+
+
+ io.dapr
+ dapr-sdk-workflows
+ ${dapr.sdk.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 17
+ 17
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.4.1
+
+
+ package
+
+ shade
+
+
+
+
+ io.dapr.quickstarts.workflows.PaymentServiceApplication
+
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+
+
+
+
+
diff --git a/workflows/multiapp/java/payment-service/src/main/java/io/dapr/quickstarts/workflows/PaymentServiceApplication.java b/workflows/multiapp/java/payment-service/src/main/java/io/dapr/quickstarts/workflows/PaymentServiceApplication.java
new file mode 100644
index 000000000..b134fad3d
--- /dev/null
+++ b/workflows/multiapp/java/payment-service/src/main/java/io/dapr/quickstarts/workflows/PaymentServiceApplication.java
@@ -0,0 +1,51 @@
+package io.dapr.quickstarts.workflows;
+
+import io.dapr.workflows.runtime.WorkflowRuntime;
+import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
+import io.dapr.quickstarts.workflows.activities.ValidatePaymentMethodActivity;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpExchange;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+
+/**
+ * PaymentServiceWorker - registers only the ValidatePaymentMethodActivity.
+ * This app will handle cross-app activity calls from the main workflow (written in Go).
+ */
+public class PaymentServiceApplication {
+
+ public static void main(String[] args) throws Exception {
+ System.out.println("=== Starting PaymentServiceWorker (ValidatePaymentMethodActivity) ===");
+
+ // Start HTTP server on port 50002
+ HttpServer server = HttpServer.create(new InetSocketAddress(50002), 0);
+ server.createContext("/health", new HealthHandler());
+ server.setExecutor(null);
+ server.start();
+ System.out.println("HTTP server started on port 50002");
+
+ WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder()
+ .registerActivity(ValidatePaymentMethodActivity.class);
+
+ // Build and start the workflow runtime
+ try (WorkflowRuntime runtime = builder.build()) {
+ System.out.println("PaymentServiceWorker started - registered ValidatePaymentMethodActivity only");
+ System.out.println("Payment Service is ready to receive multi-app activity calls...");
+ System.out.println("Waiting for multi-app activity calls...");
+ runtime.start();
+ }
+ }
+
+ static class HealthHandler implements HttpHandler {
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ String response = "Payment Service is running";
+ exchange.sendResponseHeaders(200, response.length());
+ OutputStream os = exchange.getResponseBody();
+ os.write(response.getBytes());
+ os.close();
+ }
+ }
+}
diff --git a/workflows/multiapp/java/payment-service/src/main/java/io/dapr/quickstarts/workflows/activities/ValidatePaymentMethodActivity.java b/workflows/multiapp/java/payment-service/src/main/java/io/dapr/quickstarts/workflows/activities/ValidatePaymentMethodActivity.java
new file mode 100644
index 000000000..9e295bec5
--- /dev/null
+++ b/workflows/multiapp/java/payment-service/src/main/java/io/dapr/quickstarts/workflows/activities/ValidatePaymentMethodActivity.java
@@ -0,0 +1,32 @@
+package io.dapr.quickstarts.workflows.activities;
+
+import io.dapr.workflows.WorkflowActivity;
+import io.dapr.workflows.WorkflowActivityContext;
+
+/**
+ * ValidatePaymentMethodActivity for Payment Service - validates payment methods.
+ * This activity is called cross-app from the main workflow (written in Go).
+ */
+ public class ValidatePaymentMethodActivity implements WorkflowActivity {
+ @Override
+ public Object run(WorkflowActivityContext context) {
+ var logger = context.getLogger();
+ logger.info("=== Payment Service: ValidatePaymentMethodActivity STARTED ===");
+
+ try {
+ // Get the order input
+ Object inputObj = context.getInput(Object.class);
+ logger.info("Received order: {}", inputObj);
+
+ // Simple payment validation logic
+ String result = "Payment validated successfully by payment service";
+
+ logger.info("=== Payment Service: ValidatePaymentMethodActivity COMPLETED SUCCESSFULLY ===");
+ return result;
+
+ } catch (Exception e) {
+ logger.error("ERROR in ValidatePaymentMethodActivity: {}", e.getMessage(), e);
+ throw e;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/workflows/multiapp/makefile b/workflows/multiapp/makefile
new file mode 100644
index 000000000..d2f95982c
--- /dev/null
+++ b/workflows/multiapp/makefile
@@ -0,0 +1,84 @@
+# Multi-App E-commerce Workflow Demo
+# This makefile helps you run the complete multi-app workflow scenario
+
+.PHONY: help build run-all run-go run-payment run-inventory run-ai clean
+
+# Default target
+help:
+ @echo "Multi-App E-commerce Workflow Demo"
+ @echo "=================================="
+ @echo ""
+ @echo "Available targets:"
+ @echo " build - Build all services"
+ @echo " run-all - Run all services (requires 4 terminals)"
+ @echo " run-go - Run Go Order Orchestrator"
+ @echo " run-payment - Run Java Payment Service"
+ @echo " run-inventory - Run Java Inventory Service"
+ @echo " run-ai - Run Java AI Recommendation Service"
+ @echo " clean - Clean Java build artifacts"
+ @echo ""
+
+# Build all services
+build:
+ @echo "Building Go Order Orchestrator..."
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd go && cd order-orchestrator && go mod tidy && go build -o order-orchestrator .'
+ @echo "Setting up Java environment..."
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env'
+ @echo "Building Java Payment Service..."
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env && cd payment-service && mvn clean package -q'
+ @echo "Building Java Inventory Service..."
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env && cd inventory-service && mvn clean package -q'
+ @echo "Building Java AI Recommendation Service..."
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env && cd ai-recommendation-service && mvn clean package -q'
+ @echo "All services built successfully!"
+
+# Run all services (requires 4 terminals)
+run-all:
+ @echo "Starting all services..."
+ @echo "Please open 4 terminals and run:"
+ @echo " Terminal 1: make run-go"
+ @echo " Terminal 2: make run-payment"
+ @echo " Terminal 3: make run-inventory"
+ @echo " Terminal 4: make run-ai"
+ @echo ""
+ @echo "Or run them individually:"
+ @echo " make run-go"
+ @echo " make run-payment"
+ @echo " make run-inventory"
+ @echo " make run-ai"
+
+# Run Go Order Orchestrator
+run-go:
+ @echo "Starting Go Order Orchestrator..."
+ cd go/order-orchestrator && dapr run --app-id order-orchestrator --app-port 50001 --dapr-http-port 3505 --dapr-grpc-port 50014 --resources-path ../../components -- go run .
+
+# Run Java Payment Service
+run-payment:
+ @echo "Starting Java Payment Service..."
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env && cd payment-service && dapr run --app-id payment-service --app-port 50002 --dapr-http-port 3506 --dapr-grpc-port 50015 --resources-path ../../components -- java -jar target/payment-service-1.0.0.jar'
+
+# Run Java Inventory Service
+run-inventory:
+ @echo "Starting Java Inventory Service..."
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env && cd inventory-service && dapr run --app-id inventory-service --app-port 50003 --dapr-http-port 3507 --dapr-grpc-port 50016 --resources-path ../../components -- java -jar target/inventory-service-1.0.0.jar'
+
+# Run Java AI Recommendation Service
+run-ai:
+ @echo "Starting Java AI Recommendation Service..."
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env && cd ai-recommendation-service && dapr run --app-id ai-recommendation-service --app-port 50004 --dapr-http-port 3508 --dapr-grpc-port 50017 --resources-path ../../components -- java -jar target/ai-recommendation-service-1.0.0.jar'
+
+# Clean Java build artifacts
+clean:
+ @echo "Cleaning Java build artifacts..."
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env && cd payment-service && mvn clean compile -q'
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env && cd inventory-service && mvn clean compile -q'
+ @bash -c 'source ~/.sdkman/bin/sdkman-init.sh && cd java && sdk env && cd ai-recommendation-service && mvn clean compile -q'
+ @echo "Clean completed!"
+
+# Test the workflow
+test:
+ @echo "Testing the multi-app workflow..."
+ @echo "Sending POST request to: http://localhost:50001/start-workflow"
+ @curl -X POST http://localhost:50001/start-workflow
+ @echo ""
+ @echo "Test completed!"