diff --git a/deploy.sh b/deploy.sh
index 1eeebb805e426f0e6b719a4a46936a14da8bd72f..172889c07acdc2347b2dee2ddee8bf3061fdc53a 100755
--- a/deploy.sh
+++ b/deploy.sh
@@ -91,7 +91,7 @@ for COMPONENT in $TFS_COMPONENTS; do
     fi
 
     if [ -n "$TFS_REGISTRY_IMAGE" ]; then
-        echo "Pushing Docker image to '$TFS_REGISTRY_IMAGE'..."
+        echo "  Pushing Docker image to '$TFS_REGISTRY_IMAGE'..."
 
         TAG_LOG="$TMP_LOGS_FOLDER/tag_${COMPONENT}.log"
         docker tag "$IMAGE_NAME" "$IMAGE_URL" > "$TAG_LOG"
@@ -165,7 +165,7 @@ for COMPONENT in $TFS_COMPONENTS; do
     printf "\n"
 done
 
-if [[ "$TFS_COMPONENTS" == *"webui"* ]]; then
+if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring"* ]]; then
     echo "Configuring WebUI DataStores and Dashboards..."
     sleep 3
 
diff --git a/expose_ingress_grpc.sh b/expose_ingress_grpc.sh
index 37d72aa8d66e1d2ff2e4677f245db8eaf2438ac4..8a4c837406d06ae8971a4d6ab2c5a8ae30cfc87f 100755
--- a/expose_ingress_grpc.sh
+++ b/expose_ingress_grpc.sh
@@ -37,7 +37,8 @@ for COMPONENT in $TFS_COMPONENTS; do
         continue;
     fi
 
-    PATCH='{"data": {"'${SERVICE_GRPC_PORT}'": "'$TFS_K8S_NAMESPACE'/'${COMPONENT}service':'${SERVICE_GRPC_PORT}'"}}'
+    COMPONENT_OBJNAME=$(echo "${COMPONENT}" | sed "s/\_/-/")
+    PATCH='{"data": {"'${SERVICE_GRPC_PORT}'": "'$TFS_K8S_NAMESPACE'/'${COMPONENT_OBJNAME}service':'${SERVICE_GRPC_PORT}'"}}'
     #echo "PATCH: ${PATCH}"
     kubectl patch configmap nginx-ingress-tcp-microk8s-conf --namespace ingress --patch "${PATCH}"
 
diff --git a/proto/automation.proto b/proto/automation.proto
index 02aba0a9cd3d5867a8c7f5d6581ade426ea0c290..f41bef9e28588fbd2a0acf416d347eb530c48df0 100644
--- a/proto/automation.proto
+++ b/proto/automation.proto
@@ -23,7 +23,7 @@ service AutomationService {
   rpc ZtpAdd(DeviceRole) returns (DeviceRoleState) {}
   rpc ZtpUpdate(DeviceRole) returns (DeviceRoleState) {}
   rpc ZtpDelete(DeviceRole) returns (DeviceRoleState) {}
-  rpc ZtpDeleteAll(Empty) returns (DeviceDeletionResult) {}
+  rpc ZtpDeleteAll(context.Empty) returns (DeviceDeletionResult) {}
 }
 
 enum DeviceRoleType {
@@ -56,8 +56,6 @@ message DeviceDeletionResult {
   repeated string deleted = 1;
 }
 
-message Empty {}
-
 enum ZtpDeviceState {
   ZTP_DEV_STATE_UNDEFINED = 0;
   ZTP_DEV_STATE_CREATED  = 1;
diff --git a/proto/context-policy.proto b/proto/context_policy.proto
similarity index 100%
rename from proto/context-policy.proto
rename to proto/context_policy.proto
diff --git a/proto/policy.proto b/proto/policy.proto
index c093eb17a67c2b3ff7bfa690ddd639632ae67511..0879389bf857df51b7f777fd21a4a249ff69682d 100644
--- a/proto/policy.proto
+++ b/proto/policy.proto
@@ -16,8 +16,8 @@ syntax = "proto3";
 package policy;
 
 import "context.proto";
-import "policy-condition.proto";
-import "policy-action.proto";
+import "policy_condition.proto";
+import "policy_action.proto";
 
 service PolicyService {
   rpc PolicyAddService (PolicyRuleService) returns (PolicyRuleState) {}
diff --git a/proto/policy-action.proto b/proto/policy_action.proto
similarity index 100%
rename from proto/policy-action.proto
rename to proto/policy_action.proto
diff --git a/proto/policy-condition.proto b/proto/policy_condition.proto
similarity index 100%
rename from proto/policy-condition.proto
rename to proto/policy_condition.proto
diff --git a/src/automation/src/main/java/eu/teraflow/automation/AutomationGatewayImpl.java b/src/automation/src/main/java/eu/teraflow/automation/AutomationGatewayImpl.java
index 72ab633aff296765f3a03ade814cff05b5235dfd..c160387c3e3448f29d01a185afc31127b025c2b6 100644
--- a/src/automation/src/main/java/eu/teraflow/automation/AutomationGatewayImpl.java
+++ b/src/automation/src/main/java/eu/teraflow/automation/AutomationGatewayImpl.java
@@ -80,7 +80,7 @@ public class AutomationGatewayImpl implements AutomationGateway {
     }
 
     @Override
-    public Uni<Automation.DeviceDeletionResult> ztpDeleteAll(Automation.Empty empty) {
+    public Uni<Automation.DeviceDeletionResult> ztpDeleteAll(ContextOuterClass.Empty empty) {
         return Uni.createFrom().item(() -> Automation.DeviceDeletionResult.newBuilder().build());
     }
 
diff --git a/src/automation/src/test/java/eu/teraflow/automation/AutomationServiceTest.java b/src/automation/src/test/java/eu/teraflow/automation/AutomationServiceTest.java
index d56ef139234df5da19f20364b5a93fd58ba35b4d..bd69616bcb8331919faf3ed90b6612f01a7321b9 100644
--- a/src/automation/src/test/java/eu/teraflow/automation/AutomationServiceTest.java
+++ b/src/automation/src/test/java/eu/teraflow/automation/AutomationServiceTest.java
@@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import automation.Automation;
 import automation.AutomationService;
+import context.ContextOuterClass;
 import eu.teraflow.automation.context.ContextGateway;
 import eu.teraflow.automation.context.model.ConfigActionEnum;
 import eu.teraflow.automation.context.model.ConfigRule;
@@ -236,7 +237,7 @@ class AutomationServiceTest {
     void shouldDeleteAllDevicesRolesByDeviceId()
             throws ExecutionException, InterruptedException, TimeoutException {
         CompletableFuture<String> message = new CompletableFuture<>();
-        final var empty = Automation.Empty.newBuilder().build();
+        final var empty = ContextOuterClass.Empty.newBuilder().build();
 
         client
                 .ztpDeleteAll(empty)
diff --git a/src/automation/target/generated-sources/grpc/automation/Automation.java b/src/automation/target/generated-sources/grpc/automation/Automation.java
index a44bc42294078fdba325d9dc9f149eaf1bd2bcbc..f3918e0fc18e6d97b8fd669fb307dcb94964b0e0 100644
--- a/src/automation/target/generated-sources/grpc/automation/Automation.java
+++ b/src/automation/target/generated-sources/grpc/automation/Automation.java
@@ -3977,424 +3977,6 @@ public final class Automation {
 
   }
 
-  public interface EmptyOrBuilder extends
-      // @@protoc_insertion_point(interface_extends:automation.Empty)
-      com.google.protobuf.MessageOrBuilder {
-  }
-  /**
-   * Protobuf type {@code automation.Empty}
-   */
-  public static final class Empty extends
-      com.google.protobuf.GeneratedMessageV3 implements
-      // @@protoc_insertion_point(message_implements:automation.Empty)
-      EmptyOrBuilder {
-  private static final long serialVersionUID = 0L;
-    // Use Empty.newBuilder() to construct.
-    private Empty(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
-      super(builder);
-    }
-    private Empty() {
-    }
-
-    @java.lang.Override
-    @SuppressWarnings({"unused"})
-    protected java.lang.Object newInstance(
-        UnusedPrivateParameter unused) {
-      return new Empty();
-    }
-
-    @java.lang.Override
-    public final com.google.protobuf.UnknownFieldSet
-    getUnknownFields() {
-      return this.unknownFields;
-    }
-    private Empty(
-        com.google.protobuf.CodedInputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      this();
-      if (extensionRegistry == null) {
-        throw new java.lang.NullPointerException();
-      }
-      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
-          com.google.protobuf.UnknownFieldSet.newBuilder();
-      try {
-        boolean done = false;
-        while (!done) {
-          int tag = input.readTag();
-          switch (tag) {
-            case 0:
-              done = true;
-              break;
-            default: {
-              if (!parseUnknownField(
-                  input, unknownFields, extensionRegistry, tag)) {
-                done = true;
-              }
-              break;
-            }
-          }
-        }
-      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-        throw e.setUnfinishedMessage(this);
-      } catch (java.io.IOException e) {
-        throw new com.google.protobuf.InvalidProtocolBufferException(
-            e).setUnfinishedMessage(this);
-      } finally {
-        this.unknownFields = unknownFields.build();
-        makeExtensionsImmutable();
-      }
-    }
-    public static final com.google.protobuf.Descriptors.Descriptor
-        getDescriptor() {
-      return automation.Automation.internal_static_automation_Empty_descriptor;
-    }
-
-    @java.lang.Override
-    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
-        internalGetFieldAccessorTable() {
-      return automation.Automation.internal_static_automation_Empty_fieldAccessorTable
-          .ensureFieldAccessorsInitialized(
-              automation.Automation.Empty.class, automation.Automation.Empty.Builder.class);
-    }
-
-    private byte memoizedIsInitialized = -1;
-    @java.lang.Override
-    public final boolean isInitialized() {
-      byte isInitialized = memoizedIsInitialized;
-      if (isInitialized == 1) return true;
-      if (isInitialized == 0) return false;
-
-      memoizedIsInitialized = 1;
-      return true;
-    }
-
-    @java.lang.Override
-    public void writeTo(com.google.protobuf.CodedOutputStream output)
-                        throws java.io.IOException {
-      unknownFields.writeTo(output);
-    }
-
-    @java.lang.Override
-    public int getSerializedSize() {
-      int size = memoizedSize;
-      if (size != -1) return size;
-
-      size = 0;
-      size += unknownFields.getSerializedSize();
-      memoizedSize = size;
-      return size;
-    }
-
-    @java.lang.Override
-    public boolean equals(final java.lang.Object obj) {
-      if (obj == this) {
-       return true;
-      }
-      if (!(obj instanceof automation.Automation.Empty)) {
-        return super.equals(obj);
-      }
-      automation.Automation.Empty other = (automation.Automation.Empty) obj;
-
-      if (!unknownFields.equals(other.unknownFields)) return false;
-      return true;
-    }
-
-    @java.lang.Override
-    public int hashCode() {
-      if (memoizedHashCode != 0) {
-        return memoizedHashCode;
-      }
-      int hash = 41;
-      hash = (19 * hash) + getDescriptor().hashCode();
-      hash = (29 * hash) + unknownFields.hashCode();
-      memoizedHashCode = hash;
-      return hash;
-    }
-
-    public static automation.Automation.Empty parseFrom(
-        java.nio.ByteBuffer data)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data);
-    }
-    public static automation.Automation.Empty parseFrom(
-        java.nio.ByteBuffer data,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data, extensionRegistry);
-    }
-    public static automation.Automation.Empty parseFrom(
-        com.google.protobuf.ByteString data)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data);
-    }
-    public static automation.Automation.Empty parseFrom(
-        com.google.protobuf.ByteString data,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data, extensionRegistry);
-    }
-    public static automation.Automation.Empty parseFrom(byte[] data)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data);
-    }
-    public static automation.Automation.Empty parseFrom(
-        byte[] data,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      return PARSER.parseFrom(data, extensionRegistry);
-    }
-    public static automation.Automation.Empty parseFrom(java.io.InputStream input)
-        throws java.io.IOException {
-      return com.google.protobuf.GeneratedMessageV3
-          .parseWithIOException(PARSER, input);
-    }
-    public static automation.Automation.Empty parseFrom(
-        java.io.InputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return com.google.protobuf.GeneratedMessageV3
-          .parseWithIOException(PARSER, input, extensionRegistry);
-    }
-    public static automation.Automation.Empty parseDelimitedFrom(java.io.InputStream input)
-        throws java.io.IOException {
-      return com.google.protobuf.GeneratedMessageV3
-          .parseDelimitedWithIOException(PARSER, input);
-    }
-    public static automation.Automation.Empty parseDelimitedFrom(
-        java.io.InputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return com.google.protobuf.GeneratedMessageV3
-          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
-    }
-    public static automation.Automation.Empty parseFrom(
-        com.google.protobuf.CodedInputStream input)
-        throws java.io.IOException {
-      return com.google.protobuf.GeneratedMessageV3
-          .parseWithIOException(PARSER, input);
-    }
-    public static automation.Automation.Empty parseFrom(
-        com.google.protobuf.CodedInputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws java.io.IOException {
-      return com.google.protobuf.GeneratedMessageV3
-          .parseWithIOException(PARSER, input, extensionRegistry);
-    }
-
-    @java.lang.Override
-    public Builder newBuilderForType() { return newBuilder(); }
-    public static Builder newBuilder() {
-      return DEFAULT_INSTANCE.toBuilder();
-    }
-    public static Builder newBuilder(automation.Automation.Empty prototype) {
-      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
-    }
-    @java.lang.Override
-    public Builder toBuilder() {
-      return this == DEFAULT_INSTANCE
-          ? new Builder() : new Builder().mergeFrom(this);
-    }
-
-    @java.lang.Override
-    protected Builder newBuilderForType(
-        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
-      Builder builder = new Builder(parent);
-      return builder;
-    }
-    /**
-     * Protobuf type {@code automation.Empty}
-     */
-    public static final class Builder extends
-        com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
-        // @@protoc_insertion_point(builder_implements:automation.Empty)
-        automation.Automation.EmptyOrBuilder {
-      public static final com.google.protobuf.Descriptors.Descriptor
-          getDescriptor() {
-        return automation.Automation.internal_static_automation_Empty_descriptor;
-      }
-
-      @java.lang.Override
-      protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
-          internalGetFieldAccessorTable() {
-        return automation.Automation.internal_static_automation_Empty_fieldAccessorTable
-            .ensureFieldAccessorsInitialized(
-                automation.Automation.Empty.class, automation.Automation.Empty.Builder.class);
-      }
-
-      // Construct using automation.Automation.Empty.newBuilder()
-      private Builder() {
-        maybeForceBuilderInitialization();
-      }
-
-      private Builder(
-          com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
-        super(parent);
-        maybeForceBuilderInitialization();
-      }
-      private void maybeForceBuilderInitialization() {
-        if (com.google.protobuf.GeneratedMessageV3
-                .alwaysUseFieldBuilders) {
-        }
-      }
-      @java.lang.Override
-      public Builder clear() {
-        super.clear();
-        return this;
-      }
-
-      @java.lang.Override
-      public com.google.protobuf.Descriptors.Descriptor
-          getDescriptorForType() {
-        return automation.Automation.internal_static_automation_Empty_descriptor;
-      }
-
-      @java.lang.Override
-      public automation.Automation.Empty getDefaultInstanceForType() {
-        return automation.Automation.Empty.getDefaultInstance();
-      }
-
-      @java.lang.Override
-      public automation.Automation.Empty build() {
-        automation.Automation.Empty result = buildPartial();
-        if (!result.isInitialized()) {
-          throw newUninitializedMessageException(result);
-        }
-        return result;
-      }
-
-      @java.lang.Override
-      public automation.Automation.Empty buildPartial() {
-        automation.Automation.Empty result = new automation.Automation.Empty(this);
-        onBuilt();
-        return result;
-      }
-
-      @java.lang.Override
-      public Builder clone() {
-        return super.clone();
-      }
-      @java.lang.Override
-      public Builder setField(
-          com.google.protobuf.Descriptors.FieldDescriptor field,
-          java.lang.Object value) {
-        return super.setField(field, value);
-      }
-      @java.lang.Override
-      public Builder clearField(
-          com.google.protobuf.Descriptors.FieldDescriptor field) {
-        return super.clearField(field);
-      }
-      @java.lang.Override
-      public Builder clearOneof(
-          com.google.protobuf.Descriptors.OneofDescriptor oneof) {
-        return super.clearOneof(oneof);
-      }
-      @java.lang.Override
-      public Builder setRepeatedField(
-          com.google.protobuf.Descriptors.FieldDescriptor field,
-          int index, java.lang.Object value) {
-        return super.setRepeatedField(field, index, value);
-      }
-      @java.lang.Override
-      public Builder addRepeatedField(
-          com.google.protobuf.Descriptors.FieldDescriptor field,
-          java.lang.Object value) {
-        return super.addRepeatedField(field, value);
-      }
-      @java.lang.Override
-      public Builder mergeFrom(com.google.protobuf.Message other) {
-        if (other instanceof automation.Automation.Empty) {
-          return mergeFrom((automation.Automation.Empty)other);
-        } else {
-          super.mergeFrom(other);
-          return this;
-        }
-      }
-
-      public Builder mergeFrom(automation.Automation.Empty other) {
-        if (other == automation.Automation.Empty.getDefaultInstance()) return this;
-        this.mergeUnknownFields(other.unknownFields);
-        onChanged();
-        return this;
-      }
-
-      @java.lang.Override
-      public final boolean isInitialized() {
-        return true;
-      }
-
-      @java.lang.Override
-      public Builder mergeFrom(
-          com.google.protobuf.CodedInputStream input,
-          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-          throws java.io.IOException {
-        automation.Automation.Empty parsedMessage = null;
-        try {
-          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
-        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-          parsedMessage = (automation.Automation.Empty) e.getUnfinishedMessage();
-          throw e.unwrapIOException();
-        } finally {
-          if (parsedMessage != null) {
-            mergeFrom(parsedMessage);
-          }
-        }
-        return this;
-      }
-      @java.lang.Override
-      public final Builder setUnknownFields(
-          final com.google.protobuf.UnknownFieldSet unknownFields) {
-        return super.setUnknownFields(unknownFields);
-      }
-
-      @java.lang.Override
-      public final Builder mergeUnknownFields(
-          final com.google.protobuf.UnknownFieldSet unknownFields) {
-        return super.mergeUnknownFields(unknownFields);
-      }
-
-
-      // @@protoc_insertion_point(builder_scope:automation.Empty)
-    }
-
-    // @@protoc_insertion_point(class_scope:automation.Empty)
-    private static final automation.Automation.Empty DEFAULT_INSTANCE;
-    static {
-      DEFAULT_INSTANCE = new automation.Automation.Empty();
-    }
-
-    public static automation.Automation.Empty getDefaultInstance() {
-      return DEFAULT_INSTANCE;
-    }
-
-    private static final com.google.protobuf.Parser<Empty>
-        PARSER = new com.google.protobuf.AbstractParser<Empty>() {
-      @java.lang.Override
-      public Empty parsePartialFrom(
-          com.google.protobuf.CodedInputStream input,
-          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-          throws com.google.protobuf.InvalidProtocolBufferException {
-        return new Empty(input, extensionRegistry);
-      }
-    };
-
-    public static com.google.protobuf.Parser<Empty> parser() {
-      return PARSER;
-    }
-
-    @java.lang.Override
-    public com.google.protobuf.Parser<Empty> getParserForType() {
-      return PARSER;
-    }
-
-    @java.lang.Override
-    public automation.Automation.Empty getDefaultInstanceForType() {
-      return DEFAULT_INSTANCE;
-    }
-
-  }
-
   private static final com.google.protobuf.Descriptors.Descriptor
     internal_static_automation_DeviceRoleId_descriptor;
   private static final 
@@ -4420,11 +4002,6 @@ public final class Automation {
   private static final 
     com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
       internal_static_automation_DeviceDeletionResult_fieldAccessorTable;
-  private static final com.google.protobuf.Descriptors.Descriptor
-    internal_static_automation_Empty_descriptor;
-  private static final 
-    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
-      internal_static_automation_Empty_fieldAccessorTable;
 
   public static com.google.protobuf.Descriptors.FileDescriptor
       getDescriptor() {
@@ -4445,23 +4022,23 @@ public final class Automation {
       "evRoleId\030\001 \001(\0132\030.automation.DeviceRoleId" +
       "\0220\n\014devRoleState\030\002 \001(\0162\032.automation.ZtpD" +
       "eviceState\"\'\n\024DeviceDeletionResult\022\017\n\007de" +
-      "leted\030\001 \003(\t\"\007\n\005Empty*H\n\016DeviceRoleType\022\010" +
-      "\n\004NONE\020\000\022\013\n\007DEV_OPS\020\001\022\014\n\010DEV_CONF\020\002\022\021\n\rP" +
-      "IPELINE_CONF\020\003*~\n\016ZtpDeviceState\022\033\n\027ZTP_" +
-      "DEV_STATE_UNDEFINED\020\000\022\031\n\025ZTP_DEV_STATE_C" +
-      "REATED\020\001\022\031\n\025ZTP_DEV_STATE_UPDATED\020\002\022\031\n\025Z" +
-      "TP_DEV_STATE_DELETED\020\0032\273\003\n\021AutomationSer" +
-      "vice\022F\n\020ZtpGetDeviceRole\022\030.automation.De" +
-      "viceRoleId\032\026.automation.DeviceRole\"\000\022N\n\033" +
-      "ZtpGetDeviceRolesByDeviceId\022\021.context.De" +
-      "viceId\032\032.automation.DeviceRoleList\"\000\022?\n\006" +
-      "ZtpAdd\022\026.automation.DeviceRole\032\033.automat" +
-      "ion.DeviceRoleState\"\000\022B\n\tZtpUpdate\022\026.aut" +
-      "omation.DeviceRole\032\033.automation.DeviceRo" +
-      "leState\"\000\022B\n\tZtpDelete\022\026.automation.Devi" +
-      "ceRole\032\033.automation.DeviceRoleState\"\000\022E\n" +
-      "\014ZtpDeleteAll\022\021.automation.Empty\032 .autom" +
-      "ation.DeviceDeletionResult\"\000b\006proto3"
+      "leted\030\001 \003(\t*H\n\016DeviceRoleType\022\010\n\004NONE\020\000\022" +
+      "\013\n\007DEV_OPS\020\001\022\014\n\010DEV_CONF\020\002\022\021\n\rPIPELINE_C" +
+      "ONF\020\003*~\n\016ZtpDeviceState\022\033\n\027ZTP_DEV_STATE" +
+      "_UNDEFINED\020\000\022\031\n\025ZTP_DEV_STATE_CREATED\020\001\022" +
+      "\031\n\025ZTP_DEV_STATE_UPDATED\020\002\022\031\n\025ZTP_DEV_ST" +
+      "ATE_DELETED\020\0032\270\003\n\021AutomationService\022F\n\020Z" +
+      "tpGetDeviceRole\022\030.automation.DeviceRoleI" +
+      "d\032\026.automation.DeviceRole\"\000\022N\n\033ZtpGetDev" +
+      "iceRolesByDeviceId\022\021.context.DeviceId\032\032." +
+      "automation.DeviceRoleList\"\000\022?\n\006ZtpAdd\022\026." +
+      "automation.DeviceRole\032\033.automation.Devic" +
+      "eRoleState\"\000\022B\n\tZtpUpdate\022\026.automation.D" +
+      "eviceRole\032\033.automation.DeviceRoleState\"\000" +
+      "\022B\n\tZtpDelete\022\026.automation.DeviceRole\032\033." +
+      "automation.DeviceRoleState\"\000\022B\n\014ZtpDelet" +
+      "eAll\022\016.context.Empty\032 .automation.Device" +
+      "DeletionResult\"\000b\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -4498,12 +4075,6 @@ public final class Automation {
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_automation_DeviceDeletionResult_descriptor,
         new java.lang.String[] { "Deleted", });
-    internal_static_automation_Empty_descriptor =
-      getDescriptor().getMessageTypes().get(5);
-    internal_static_automation_Empty_fieldAccessorTable = new
-      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
-        internal_static_automation_Empty_descriptor,
-        new java.lang.String[] { });
     context.ContextOuterClass.getDescriptor();
   }
 
diff --git a/src/automation/target/generated-sources/grpc/automation/AutomationService.java b/src/automation/target/generated-sources/grpc/automation/AutomationService.java
index 9b772a499617f341ba742ccfe8ae8ade34366831..4df9e1098d2028bba58da0959512310ed3d2c4ba 100644
--- a/src/automation/target/generated-sources/grpc/automation/AutomationService.java
+++ b/src/automation/target/generated-sources/grpc/automation/AutomationService.java
@@ -18,7 +18,7 @@ public interface AutomationService extends MutinyService {
     
     io.smallrye.mutiny.Uni<automation.Automation.DeviceRoleState> ztpDelete(automation.Automation.DeviceRole request);
     
-    io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(automation.Automation.Empty request);
+    io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(context.ContextOuterClass.Empty request);
     
     
     
diff --git a/src/automation/target/generated-sources/grpc/automation/AutomationServiceBean.java b/src/automation/target/generated-sources/grpc/automation/AutomationServiceBean.java
index 52b1425cf6d3c5c59ae99621204689176892d043..74d420a1ee8c3c11f824c30fb96f694ddddc64fe 100644
--- a/src/automation/target/generated-sources/grpc/automation/AutomationServiceBean.java
+++ b/src/automation/target/generated-sources/grpc/automation/AutomationServiceBean.java
@@ -56,7 +56,7 @@ public class AutomationServiceBean extends MutinyAutomationServiceGrpc.Automatio
        }
     }
     @Override
-    public io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(automation.Automation.Empty request) {
+    public io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(context.ContextOuterClass.Empty request) {
        try {
          return delegate.ztpDeleteAll(request);
        } catch (UnsupportedOperationException e) {
diff --git a/src/automation/target/generated-sources/grpc/automation/AutomationServiceClient.java b/src/automation/target/generated-sources/grpc/automation/AutomationServiceClient.java
index 5dde73d5bfdbb401ed9fd89e38a6caa3e75cabbe..9dcad532a0238f6f14d8e6ca2aa64b445747e9e6 100644
--- a/src/automation/target/generated-sources/grpc/automation/AutomationServiceClient.java
+++ b/src/automation/target/generated-sources/grpc/automation/AutomationServiceClient.java
@@ -41,7 +41,7 @@ public class AutomationServiceClient implements AutomationService, MutinyClient<
        return stub.ztpDelete(request);
     }
     @Override
-    public io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(automation.Automation.Empty request) {
+    public io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(context.ContextOuterClass.Empty request) {
        return stub.ztpDeleteAll(request);
     }
 
diff --git a/src/automation/target/generated-sources/grpc/automation/AutomationServiceGrpc.java b/src/automation/target/generated-sources/grpc/automation/AutomationServiceGrpc.java
index 9f805796624bff8dfbd5f4b428fa21cf066ffb80..25f5feaf327702102d1ec6cd9ca6cc8ab74cf14f 100644
--- a/src/automation/target/generated-sources/grpc/automation/AutomationServiceGrpc.java
+++ b/src/automation/target/generated-sources/grpc/automation/AutomationServiceGrpc.java
@@ -169,27 +169,27 @@ public final class AutomationServiceGrpc {
     return getZtpDeleteMethod;
   }
 
-  private static volatile io.grpc.MethodDescriptor<automation.Automation.Empty,
+  private static volatile io.grpc.MethodDescriptor<context.ContextOuterClass.Empty,
       automation.Automation.DeviceDeletionResult> getZtpDeleteAllMethod;
 
   @io.grpc.stub.annotations.RpcMethod(
       fullMethodName = SERVICE_NAME + '/' + "ZtpDeleteAll",
-      requestType = automation.Automation.Empty.class,
+      requestType = context.ContextOuterClass.Empty.class,
       responseType = automation.Automation.DeviceDeletionResult.class,
       methodType = io.grpc.MethodDescriptor.MethodType.UNARY)
-  public static io.grpc.MethodDescriptor<automation.Automation.Empty,
+  public static io.grpc.MethodDescriptor<context.ContextOuterClass.Empty,
       automation.Automation.DeviceDeletionResult> getZtpDeleteAllMethod() {
-    io.grpc.MethodDescriptor<automation.Automation.Empty, automation.Automation.DeviceDeletionResult> getZtpDeleteAllMethod;
+    io.grpc.MethodDescriptor<context.ContextOuterClass.Empty, automation.Automation.DeviceDeletionResult> getZtpDeleteAllMethod;
     if ((getZtpDeleteAllMethod = AutomationServiceGrpc.getZtpDeleteAllMethod) == null) {
       synchronized (AutomationServiceGrpc.class) {
         if ((getZtpDeleteAllMethod = AutomationServiceGrpc.getZtpDeleteAllMethod) == null) {
           AutomationServiceGrpc.getZtpDeleteAllMethod = getZtpDeleteAllMethod =
-              io.grpc.MethodDescriptor.<automation.Automation.Empty, automation.Automation.DeviceDeletionResult>newBuilder()
+              io.grpc.MethodDescriptor.<context.ContextOuterClass.Empty, automation.Automation.DeviceDeletionResult>newBuilder()
               .setType(io.grpc.MethodDescriptor.MethodType.UNARY)
               .setFullMethodName(generateFullMethodName(SERVICE_NAME, "ZtpDeleteAll"))
               .setSampledToLocalTracing(true)
               .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
-                  automation.Automation.Empty.getDefaultInstance()))
+                  context.ContextOuterClass.Empty.getDefaultInstance()))
               .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller(
                   automation.Automation.DeviceDeletionResult.getDefaultInstance()))
               .setSchemaDescriptor(new AutomationServiceMethodDescriptorSupplier("ZtpDeleteAll"))
@@ -285,7 +285,7 @@ public final class AutomationServiceGrpc {
 
     /**
      */
-    public void ztpDeleteAll(automation.Automation.Empty request,
+    public void ztpDeleteAll(context.ContextOuterClass.Empty request,
         io.grpc.stub.StreamObserver<automation.Automation.DeviceDeletionResult> responseObserver) {
       io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getZtpDeleteAllMethod(), responseObserver);
     }
@@ -331,7 +331,7 @@ public final class AutomationServiceGrpc {
             getZtpDeleteAllMethod(),
             io.grpc.stub.ServerCalls.asyncUnaryCall(
               new MethodHandlers<
-                automation.Automation.Empty,
+                context.ContextOuterClass.Empty,
                 automation.Automation.DeviceDeletionResult>(
                   this, METHODID_ZTP_DELETE_ALL)))
           .build();
@@ -394,7 +394,7 @@ public final class AutomationServiceGrpc {
 
     /**
      */
-    public void ztpDeleteAll(automation.Automation.Empty request,
+    public void ztpDeleteAll(context.ContextOuterClass.Empty request,
         io.grpc.stub.StreamObserver<automation.Automation.DeviceDeletionResult> responseObserver) {
       io.grpc.stub.ClientCalls.asyncUnaryCall(
           getChannel().newCall(getZtpDeleteAllMethod(), getCallOptions()), request, responseObserver);
@@ -452,7 +452,7 @@ public final class AutomationServiceGrpc {
 
     /**
      */
-    public automation.Automation.DeviceDeletionResult ztpDeleteAll(automation.Automation.Empty request) {
+    public automation.Automation.DeviceDeletionResult ztpDeleteAll(context.ContextOuterClass.Empty request) {
       return io.grpc.stub.ClientCalls.blockingUnaryCall(
           getChannel(), getZtpDeleteAllMethod(), getCallOptions(), request);
     }
@@ -515,7 +515,7 @@ public final class AutomationServiceGrpc {
     /**
      */
     public com.google.common.util.concurrent.ListenableFuture<automation.Automation.DeviceDeletionResult> ztpDeleteAll(
-        automation.Automation.Empty request) {
+        context.ContextOuterClass.Empty request) {
       return io.grpc.stub.ClientCalls.futureUnaryCall(
           getChannel().newCall(getZtpDeleteAllMethod(), getCallOptions()), request);
     }
@@ -566,7 +566,7 @@ public final class AutomationServiceGrpc {
               (io.grpc.stub.StreamObserver<automation.Automation.DeviceRoleState>) responseObserver);
           break;
         case METHODID_ZTP_DELETE_ALL:
-          serviceImpl.ztpDeleteAll((automation.Automation.Empty) request,
+          serviceImpl.ztpDeleteAll((context.ContextOuterClass.Empty) request,
               (io.grpc.stub.StreamObserver<automation.Automation.DeviceDeletionResult>) responseObserver);
           break;
         default:
diff --git a/src/automation/target/generated-sources/grpc/automation/MutinyAutomationServiceGrpc.java b/src/automation/target/generated-sources/grpc/automation/MutinyAutomationServiceGrpc.java
index 0783cbc965e487a020a36d25acca55c5a17c0640..9b641fcdd7733828c58ce563651ac3d46e697287 100644
--- a/src/automation/target/generated-sources/grpc/automation/MutinyAutomationServiceGrpc.java
+++ b/src/automation/target/generated-sources/grpc/automation/MutinyAutomationServiceGrpc.java
@@ -61,7 +61,7 @@ public final class MutinyAutomationServiceGrpc implements io.quarkus.grpc.runtim
         }
 
         
-        public io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(automation.Automation.Empty request) {
+        public io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(context.ContextOuterClass.Empty request) {
             return io.quarkus.grpc.runtime.ClientCalls.oneToOne(request, delegateStub::ztpDeleteAll);
         }
 
@@ -108,7 +108,7 @@ public final class MutinyAutomationServiceGrpc implements io.quarkus.grpc.runtim
         }
 
         
-        public io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(automation.Automation.Empty request) {
+        public io.smallrye.mutiny.Uni<automation.Automation.DeviceDeletionResult> ztpDeleteAll(context.ContextOuterClass.Empty request) {
             throw new io.grpc.StatusRuntimeException(io.grpc.Status.UNIMPLEMENTED);
         }
 
@@ -153,7 +153,7 @@ public final class MutinyAutomationServiceGrpc implements io.quarkus.grpc.runtim
                             automation.AutomationServiceGrpc.getZtpDeleteAllMethod(),
                             asyncUnaryCall(
                                     new MethodHandlers<
-                                            automation.Automation.Empty,
+                                            context.ContextOuterClass.Empty,
                                             automation.Automation.DeviceDeletionResult>(
                                             this, METHODID_ZTP_DELETE_ALL, compression)))
                     .build();
@@ -217,7 +217,7 @@ public final class MutinyAutomationServiceGrpc implements io.quarkus.grpc.runtim
                             serviceImpl::ztpDelete);
                     break;
                 case METHODID_ZTP_DELETE_ALL:
-                    io.quarkus.grpc.runtime.ServerCalls.oneToOne((automation.Automation.Empty) request,
+                    io.quarkus.grpc.runtime.ServerCalls.oneToOne((context.ContextOuterClass.Empty) request,
                             (io.grpc.stub.StreamObserver<automation.Automation.DeviceDeletionResult>) responseObserver,
                             compression,
                             serviceImpl::ztpDeleteAll);
diff --git a/src/automation/target/kubernetes/kubernetes.yml b/src/automation/target/kubernetes/kubernetes.yml
index 5fa64eaa3ff3f5f32659f226ee892ec78f5eedd2..321ce20d110da0042b427af531a4473abde0721a 100644
--- a/src/automation/target/kubernetes/kubernetes.yml
+++ b/src/automation/target/kubernetes/kubernetes.yml
@@ -3,20 +3,20 @@ apiVersion: v1
 kind: Service
 metadata:
   annotations:
-    app.quarkus.io/commit-id: cc97cda43489c948a3267ddcb2833ae67f5880cc
-    app.quarkus.io/build-timestamp: 2022-07-22 - 11:36:51 +0000
+    app.quarkus.io/commit-id: 70662d960465062d0c21ccce778af4ddb5619bec
+    app.quarkus.io/build-timestamp: 2022-08-01 - 11:18:43 +0000
   labels:
     app.kubernetes.io/name: automationservice
     app: automationservice
   name: automationservice
 spec:
   ports:
-    - name: grpc
-      port: 5050
-      targetPort: 5050
     - name: http
       port: 8080
       targetPort: 8080
+    - name: grpc
+      port: 5050
+      targetPort: 5050
   selector:
     app.kubernetes.io/name: automationservice
   type: ClusterIP
@@ -25,8 +25,8 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   annotations:
-    app.quarkus.io/commit-id: cc97cda43489c948a3267ddcb2833ae67f5880cc
-    app.quarkus.io/build-timestamp: 2022-07-22 - 11:36:51 +0000
+    app.quarkus.io/commit-id: 70662d960465062d0c21ccce778af4ddb5619bec
+    app.quarkus.io/build-timestamp: 2022-08-01 - 11:18:43 +0000
   labels:
     app: automationservice
     app.kubernetes.io/name: automationservice
@@ -39,8 +39,8 @@ spec:
   template:
     metadata:
       annotations:
-        app.quarkus.io/commit-id: cc97cda43489c948a3267ddcb2833ae67f5880cc
-        app.quarkus.io/build-timestamp: 2022-07-22 - 11:36:51 +0000
+        app.quarkus.io/commit-id: 70662d960465062d0c21ccce778af4ddb5619bec
+        app.quarkus.io/build-timestamp: 2022-08-01 - 11:18:43 +0000
       labels:
         app: automationservice
         app.kubernetes.io/name: automationservice
@@ -51,10 +51,10 @@ spec:
               valueFrom:
                 fieldRef:
                   fieldPath: metadata.namespace
-            - name: DEVICE_SERVICE_HOST
-              value: DeviceService
             - name: CONTEXT_SERVICE_HOST
               value: ContextService
+            - name: DEVICE_SERVICE_HOST
+              value: DeviceService
           image: registry.gitlab.com/teraflow-h2020/controller/automation:0.2.0
           imagePullPolicy: Always
           livenessProbe:
@@ -69,12 +69,12 @@ spec:
             timeoutSeconds: 10
           name: automationservice
           ports:
-            - containerPort: 5050
-              name: grpc
-              protocol: TCP
             - containerPort: 8080
               name: http
               protocol: TCP
+            - containerPort: 5050
+              name: grpc
+              protocol: TCP
           readinessProbe:
             failureThreshold: 3
             httpGet:
diff --git a/src/policy/src/main/java/eu/teraflow/policy/PolicyGatewayImpl.java b/src/policy/src/main/java/eu/teraflow/policy/PolicyGatewayImpl.java
index 642fabcba92c82cab8cc0c43dca805aa95231df6..c76f8c8c402d454af88349ce14ae53f0a0c69f3d 100644
--- a/src/policy/src/main/java/eu/teraflow/policy/PolicyGatewayImpl.java
+++ b/src/policy/src/main/java/eu/teraflow/policy/PolicyGatewayImpl.java
@@ -33,32 +33,32 @@ import policy.Policy.RuleState;
 public class PolicyGatewayImpl implements PolicyGateway {
 
     private final PolicyService policyService;
+    private final Serializer serializer;
 
     @Inject
-    public PolicyGatewayImpl(PolicyService policyService) {
+    public PolicyGatewayImpl(PolicyService policyService, Serializer serializer) {
         this.policyService = policyService;
+        this.serializer = serializer;
     }
 
     @Override
     public Uni<PolicyRuleState> policyAddService(PolicyRuleService request) {
-        return Uni.createFrom()
-                .item(
-                        () ->
-                                Policy.PolicyRuleState.newBuilder()
-                                        .setPolicyRuleState(
-                                                request.getPolicyRuleBasic().getPolicyRuleState().getPolicyRuleState())
-                                        .build());
+        final var policyRuleService = serializer.deserialize(request);
+
+        return policyService
+                .addPolicyService(policyRuleService)
+                .onItem()
+                .transform(serializer::serialize);
     }
 
     @Override
     public Uni<PolicyRuleState> policyAddDevice(PolicyRuleDevice request) {
-        return Uni.createFrom()
-                .item(
-                        () ->
-                                Policy.PolicyRuleState.newBuilder()
-                                        .setPolicyRuleState(
-                                                request.getPolicyRuleBasic().getPolicyRuleState().getPolicyRuleState())
-                                        .build());
+        final var policyRuleDevice = serializer.deserialize(request);
+
+        return policyService
+                .addPolicyDevice(policyRuleDevice)
+                .onItem()
+                .transform(serializer::serialize);
     }
 
     @Override
diff --git a/src/policy/src/main/java/eu/teraflow/policy/PolicyService.java b/src/policy/src/main/java/eu/teraflow/policy/PolicyService.java
index 14ffbb41ef60a438990bfe59e1d9539b48b51d75..dcaf43b902c95471cff2c020f0fdc5659c59e6a1 100644
--- a/src/policy/src/main/java/eu/teraflow/policy/PolicyService.java
+++ b/src/policy/src/main/java/eu/teraflow/policy/PolicyService.java
@@ -16,10 +16,10 @@
 
 package eu.teraflow.policy;
 
+import eu.teraflow.policy.model.PolicyRuleDevice;
+import eu.teraflow.policy.model.PolicyRuleService;
 import eu.teraflow.policy.model.PolicyRuleState;
 import io.smallrye.mutiny.Uni;
-import policy.Policy.PolicyRuleDevice;
-import policy.Policy.PolicyRuleService;
 
 public interface PolicyService {
 
diff --git a/src/policy/src/main/java/eu/teraflow/policy/PolicyServiceImpl.java b/src/policy/src/main/java/eu/teraflow/policy/PolicyServiceImpl.java
index c9645c5e30b1b4380bb9c0004a8b66f734f279d1..66994625ddb2eb6a52e1d0a99acd52a2cd1cc2f2 100644
--- a/src/policy/src/main/java/eu/teraflow/policy/PolicyServiceImpl.java
+++ b/src/policy/src/main/java/eu/teraflow/policy/PolicyServiceImpl.java
@@ -16,25 +16,48 @@
 
 package eu.teraflow.policy;
 
+import eu.teraflow.policy.context.ContextService;
+import eu.teraflow.policy.model.PolicyRuleDevice;
+import eu.teraflow.policy.model.PolicyRuleService;
 import eu.teraflow.policy.model.PolicyRuleState;
+import eu.teraflow.policy.model.RuleState;
+import eu.teraflow.policy.monitoring.MonitoringService;
+import eu.teraflow.policy.service.ServiceService;
 import io.smallrye.mutiny.Uni;
 import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
 import org.jboss.logging.Logger;
-import policy.Policy.PolicyRuleDevice;
-import policy.Policy.PolicyRuleService;
 
 @ApplicationScoped
 public class PolicyServiceImpl implements PolicyService {
 
     private static final Logger LOGGER = Logger.getLogger(PolicyServiceImpl.class);
 
+    private final ContextService contextService;
+    private final MonitoringService monitoringService;
+    private final ServiceService serviceService;
+
+    @Inject
+    public PolicyServiceImpl(
+            ContextService contextService,
+            MonitoringService monitoringService,
+            ServiceService serviceService) {
+        this.contextService = contextService;
+        this.monitoringService = monitoringService;
+        this.serviceService = serviceService;
+    }
+
     @Override
     public Uni<PolicyRuleState> addPolicyService(PolicyRuleService policyRuleService) {
-        return null;
+        final var policyRuleState = new PolicyRuleState(RuleState.POLICY_VALIDATED);
+
+        return Uni.createFrom().item(policyRuleState);
     }
 
     @Override
     public Uni<PolicyRuleState> addPolicyDevice(PolicyRuleDevice policyRuleDevice) {
-        return null;
+        final var policyRuleState = new PolicyRuleState(RuleState.POLICY_VALIDATED);
+
+        return Uni.createFrom().item(policyRuleState);
     }
 }
diff --git a/src/policy/src/main/java/eu/teraflow/policy/context/ContextGatewayImpl.java b/src/policy/src/main/java/eu/teraflow/policy/context/ContextGatewayImpl.java
index 3af300d4914ef589d380c32a3389383c5dd37c0d..6185b4e9a334f5b5c24faec348877c352e945511 100644
--- a/src/policy/src/main/java/eu/teraflow/policy/context/ContextGatewayImpl.java
+++ b/src/policy/src/main/java/eu/teraflow/policy/context/ContextGatewayImpl.java
@@ -34,7 +34,7 @@ public class ContextGatewayImpl implements ContextGateway {
     @GrpcClient("context")
     MutinyContextServiceStub streamingDelegateContext;
 
-    // TODO remove client when RPCs declared in context-policy.proto are moved in context.proto
+    // TODO remove client when RPCs declared in context_policy.proto are moved in context.proto
     //  and use streamingDelegateContext for all methods
     @GrpcClient("context_policy")
     MutinyContextPolicyServiceStub streamingDelegateContextPolicy;
diff --git a/src/policy/src/main/proto/context-policy.proto b/src/policy/src/main/proto/context-policy.proto
deleted file mode 120000
index 5c0888e9edf15c8fa540e85afabb98342c0e0c51..0000000000000000000000000000000000000000
--- a/src/policy/src/main/proto/context-policy.proto
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../proto/context-policy.proto
\ No newline at end of file
diff --git a/src/policy/src/main/proto/context_policy.proto b/src/policy/src/main/proto/context_policy.proto
new file mode 120000
index 0000000000000000000000000000000000000000..d41593ddeb8b8b89878587e4fb389c94394ab340
--- /dev/null
+++ b/src/policy/src/main/proto/context_policy.proto
@@ -0,0 +1 @@
+../../../../../proto/context_policy.proto
\ No newline at end of file
diff --git a/src/policy/src/main/proto/policy-action.proto b/src/policy/src/main/proto/policy-action.proto
deleted file mode 120000
index bb1531bd6607ff005fdaae9d0be27ee65e3515ca..0000000000000000000000000000000000000000
--- a/src/policy/src/main/proto/policy-action.proto
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../proto/policy-action.proto
\ No newline at end of file
diff --git a/src/policy/src/main/proto/policy-condition.proto b/src/policy/src/main/proto/policy-condition.proto
deleted file mode 120000
index f847d8b602252979135ead0876c50a161f049a72..0000000000000000000000000000000000000000
--- a/src/policy/src/main/proto/policy-condition.proto
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../proto/policy-condition.proto
\ No newline at end of file
diff --git a/src/policy/src/main/proto/policy_action.proto b/src/policy/src/main/proto/policy_action.proto
new file mode 120000
index 0000000000000000000000000000000000000000..63dcef3d2c6753f9b732dc7491baa5f449e55eff
--- /dev/null
+++ b/src/policy/src/main/proto/policy_action.proto
@@ -0,0 +1 @@
+../../../../../proto/policy_action.proto
\ No newline at end of file
diff --git a/src/policy/src/main/proto/policy_condition.proto b/src/policy/src/main/proto/policy_condition.proto
new file mode 120000
index 0000000000000000000000000000000000000000..31f7d9d10539de8c0a1bf06cf6393b86ab223c16
--- /dev/null
+++ b/src/policy/src/main/proto/policy_condition.proto
@@ -0,0 +1 @@
+../../../../../proto/policy_condition.proto
\ No newline at end of file
diff --git a/src/policy/src/test/java/eu/teraflow/policy/PolicyServiceTest.java b/src/policy/src/test/java/eu/teraflow/policy/PolicyServiceTest.java
index bf1af532f06accf9c0410548ad7f4aa85757dbb1..7e3044c1d2212d6bf8726c55673ff84e5d174f4f 100644
--- a/src/policy/src/test/java/eu/teraflow/policy/PolicyServiceTest.java
+++ b/src/policy/src/test/java/eu/teraflow/policy/PolicyServiceTest.java
@@ -19,18 +19,30 @@ package eu.teraflow.policy;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import context.ContextOuterClass;
+import context.ContextOuterClass.Uuid;
+import eu.teraflow.policy.monitoring.model.FloatKpiValue;
+import eu.teraflow.policy.monitoring.model.IntegerKpiValue;
 import io.quarkus.grpc.GrpcClient;
 import io.quarkus.test.junit.QuarkusTest;
+import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import javax.inject.Inject;
+import monitoring.Monitoring.KpiId;
 import org.jboss.logging.Logger;
 import org.junit.jupiter.api.Test;
 import policy.Policy;
 import policy.Policy.PolicyRuleBasic;
 import policy.Policy.RuleState;
+import policy.PolicyAction;
+import policy.PolicyAction.PolicyRuleActionEnum;
+import policy.PolicyCondition;
+import policy.PolicyCondition.BooleanOperator;
+import policy.PolicyCondition.NumericalOperator;
+import policy.PolicyCondition.PolicyRuleCondition;
 import policy.PolicyService;
 
 @QuarkusTest
@@ -38,16 +50,84 @@ class PolicyServiceTest {
     private static final Logger LOGGER = Logger.getLogger(PolicyServiceTest.class);
 
     @GrpcClient PolicyService client;
+    private final Serializer serializer;
+
+    @Inject
+    PolicyServiceTest(Serializer serializer) {
+        this.serializer = serializer;
+    }
+
+    private PolicyRuleBasic createPolicyRuleBasic() {
+        final var expectedPolicyRuleIdUuid =
+                serializer.serializeUuid("571eabc1-0f59-48da-b608-c45876c3fa8a");
+
+        final var expectedPolicyRuleId =
+                Policy.PolicyRuleId.newBuilder().setUuid(expectedPolicyRuleIdUuid).build();
+
+        final var expectedPolicyRuleState =
+                Policy.PolicyRuleState.newBuilder().setPolicyRuleState(RuleState.POLICY_VALIDATED).build();
+
+        final var expectedFirstKpiValue = new IntegerKpiValue(22);
+        final var expectedSecondKpiValue = new FloatKpiValue(69.1f);
+
+        final var serializedExpectedFirstKpiValue = serializer.serialize(expectedFirstKpiValue);
+        final var serializedExpectedSecondKpiValue = serializer.serialize(expectedSecondKpiValue);
+
+        final var firstExpectedPolicyRuleCondition =
+                PolicyRuleCondition.newBuilder()
+                        .setKpiId(
+                                KpiId.newBuilder()
+                                        .setKpiId(
+                                                Uuid.newBuilder().setUuid("79e49ba3-a7b4-4b4b-8aaa-28b05c6f888e").build()))
+                        .setNumericalOperator(NumericalOperator.POLICYRULE_CONDITION_NUMERICAL_EQUAL)
+                        .setKpiValue(serializedExpectedFirstKpiValue)
+                        .build();
+
+        final var secondExpectedPolicyRuleCondition =
+                PolicyCondition.PolicyRuleCondition.newBuilder()
+                        .setKpiId(
+                                KpiId.newBuilder()
+                                        .setKpiId(
+                                                Uuid.newBuilder().setUuid("eae900e5-2703-467d-82f2-97aae8b55c15").build()))
+                        .setNumericalOperator(NumericalOperator.POLICYRULE_CONDITION_NUMERICAL_GREATER_THAN)
+                        .setKpiValue(serializedExpectedSecondKpiValue)
+                        .build();
+
+        final var expectedPolicyRuleConditions =
+                List.of(firstExpectedPolicyRuleCondition, secondExpectedPolicyRuleCondition);
+
+        final var firstExpectedPolicyRuleAction =
+                PolicyAction.PolicyRuleAction.newBuilder()
+                        .setAction(PolicyAction.PolicyRuleActionEnum.POLICYRULE_ACTION_ADD_SERVICE_CONFIGRULE)
+                        .addAllParameters(List.of("parameter1", "parameter2"))
+                        .build();
+
+        final var secondExpectedPolicyRuleAction =
+                PolicyAction.PolicyRuleAction.newBuilder()
+                        .setAction(PolicyRuleActionEnum.POLICYRULE_ACTION_ADD_SERVICE_CONSTRAINT)
+                        .addAllParameters(List.of("parameter3", "parameter4"))
+                        .build();
+
+        final var expectedPolicyRuleActions =
+                List.of(firstExpectedPolicyRuleAction, secondExpectedPolicyRuleAction);
+
+        return PolicyRuleBasic.newBuilder()
+                .setPolicyRuleId(expectedPolicyRuleId)
+                .setPolicyRuleState(expectedPolicyRuleState)
+                .addAllConditionList(expectedPolicyRuleConditions)
+                .setBooleanOperator(BooleanOperator.POLICYRULE_CONDITION_BOOLEAN_OR)
+                .addAllActionList(expectedPolicyRuleActions)
+                .build();
+    }
 
     @Test
     void shouldAddPolicyService() throws ExecutionException, InterruptedException, TimeoutException {
         CompletableFuture<String> message = new CompletableFuture<>();
 
-        final var expectedPolicyRuleState =
-                Policy.PolicyRuleState.newBuilder().setPolicyRuleState(RuleState.POLICY_ACTIVE).build();
+        final var policyRuleBasic = createPolicyRuleBasic();
+
+        final var expectedPolicyRuleState = policyRuleBasic.getPolicyRuleState();
 
-        final var policyRuleBasic =
-                PolicyRuleBasic.newBuilder().setPolicyRuleState(expectedPolicyRuleState).build();
         final var policyRuleService =
                 Policy.PolicyRuleService.newBuilder().setPolicyRuleBasic(policyRuleBasic).build();
 
@@ -64,11 +144,9 @@ class PolicyServiceTest {
     void shouldAddPolicyDevice() throws ExecutionException, InterruptedException, TimeoutException {
         CompletableFuture<String> message = new CompletableFuture<>();
 
-        final var expectedPolicyRuleState =
-                Policy.PolicyRuleState.newBuilder().setPolicyRuleState(RuleState.POLICY_EFFECTIVE).build();
+        final var policyRuleBasic = createPolicyRuleBasic();
+        final var expectedPolicyRuleState = policyRuleBasic.getPolicyRuleState();
 
-        final var policyRuleBasic =
-                PolicyRuleBasic.newBuilder().setPolicyRuleState(expectedPolicyRuleState).build();
         final var policyRuleDevice =
                 Policy.PolicyRuleDevice.newBuilder().setPolicyRuleBasic(policyRuleBasic).build();
 
diff --git a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicy.java b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicy.java
index 5048be4750db97e35f3007645927f2c7ea24be85..455aef779d7a0c29a4654b895e6c9652ca416e14 100644
--- a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicy.java
+++ b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicy.java
@@ -1,5 +1,5 @@
 // Generated by the protocol buffer compiler.  DO NOT EDIT!
-// source: context-policy.proto
+// source: context_policy.proto
 
 package context_policy;
 
@@ -23,7 +23,7 @@ public final class ContextPolicy {
       descriptor;
   static {
     java.lang.String[] descriptorData = {
-      "\n\024context-policy.proto\022\016context_policy\032\r" +
+      "\n\024context_policy.proto\022\016context_policy\032\r" +
       "context.proto\032\014policy.proto2\324\002\n\024ContextP" +
       "olicyService\022?\n\021ListPolicyRuleIds\022\016.cont" +
       "ext.Empty\032\030.policy.PolicyRuleIdList\"\000\022;\n" +
diff --git a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyService.java b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyService.java
index 4870737ab496fff5c36ffa0824e44669532ecec0..7ace0b9dcf220b80359a47781c1f8cdc1d9984ea 100644
--- a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyService.java
+++ b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyService.java
@@ -4,7 +4,7 @@ import io.quarkus.grpc.runtime.MutinyService;
 
 @javax.annotation.Generated(
 value = "by Mutiny Grpc generator",
-comments = "Source: context-policy.proto")
+comments = "Source: context_policy.proto")
 public interface ContextPolicyService extends MutinyService {
 
     
diff --git a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceBean.java b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceBean.java
index b1a93a6014a9fb0d9ae0d0e528fda1a1e2658416..a08761c67c484d5b35d22253364ccaf6beaa266c 100644
--- a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceBean.java
+++ b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceBean.java
@@ -6,7 +6,7 @@ import io.quarkus.grpc.runtime.MutinyBean;
 
 @javax.annotation.Generated(
 value = "by Mutiny Grpc generator",
-comments = "Source: context-policy.proto")
+comments = "Source: context_policy.proto")
 public class ContextPolicyServiceBean extends MutinyContextPolicyServiceGrpc.ContextPolicyServiceImplBase implements BindableService, MutinyBean {
 
     private final ContextPolicyService delegate;
diff --git a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceClient.java b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceClient.java
index d255415707710db2b225f4d4f7e3f7c4ee6fd6d5..98e57eeff41027e644057dced751b78837fd5fe3 100644
--- a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceClient.java
+++ b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceClient.java
@@ -6,7 +6,7 @@ import io.quarkus.grpc.runtime.MutinyClient;
 
 @javax.annotation.Generated(
 value = "by Mutiny Grpc generator",
-comments = "Source: context-policy.proto")
+comments = "Source: context_policy.proto")
 public class ContextPolicyServiceClient implements ContextPolicyService, MutinyClient<MutinyContextPolicyServiceGrpc.MutinyContextPolicyServiceStub> {
 
     private final MutinyContextPolicyServiceGrpc.MutinyContextPolicyServiceStub stub;
diff --git a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceGrpc.java b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceGrpc.java
index 69735c34ce57d91725f81c7c23d94ad60da1db9b..fa859ecff706640410d852ec129c359cb38be990 100644
--- a/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceGrpc.java
+++ b/src/policy/target/generated-sources/grpc/context_policy/ContextPolicyServiceGrpc.java
@@ -9,7 +9,7 @@ import static io.grpc.MethodDescriptor.generateFullMethodName;
  */
 @javax.annotation.Generated(
     value = "by gRPC proto compiler (version 1.38.1)",
-    comments = "Source: context-policy.proto")
+    comments = "Source: context_policy.proto")
 public final class ContextPolicyServiceGrpc {
 
   private ContextPolicyServiceGrpc() {}
diff --git a/src/policy/target/generated-sources/grpc/context_policy/MutinyContextPolicyServiceGrpc.java b/src/policy/target/generated-sources/grpc/context_policy/MutinyContextPolicyServiceGrpc.java
index 6e6e29c0468afe5656d537cd0fe79e7b9ede7bad..d9ff3b64cb48b70406954b72ace59035283ba701 100644
--- a/src/policy/target/generated-sources/grpc/context_policy/MutinyContextPolicyServiceGrpc.java
+++ b/src/policy/target/generated-sources/grpc/context_policy/MutinyContextPolicyServiceGrpc.java
@@ -8,7 +8,7 @@ import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
 
 @javax.annotation.Generated(
 value = "by Mutiny Grpc generator",
-comments = "Source: context-policy.proto")
+comments = "Source: context_policy.proto")
 public final class MutinyContextPolicyServiceGrpc implements io.quarkus.grpc.runtime.MutinyGrpc {
     private MutinyContextPolicyServiceGrpc() {}
 
diff --git a/src/policy/target/generated-sources/grpc/policy/Policy.java b/src/policy/target/generated-sources/grpc/policy/Policy.java
index 541f97f47bd2e69711a795dc454841054e865a3a..08ce14adab068743fd26f031a82ec5fd56693c09 100644
--- a/src/policy/target/generated-sources/grpc/policy/Policy.java
+++ b/src/policy/target/generated-sources/grpc/policy/Policy.java
@@ -9387,7 +9387,7 @@ public final class Policy {
   static {
     java.lang.String[] descriptorData = {
       "\n\014policy.proto\022\006policy\032\rcontext.proto\032\026p" +
-      "olicy-condition.proto\032\023policy-action.pro" +
+      "olicy_condition.proto\032\023policy_action.pro" +
       "to\"+\n\014PolicyRuleId\022\033\n\004uuid\030\001 \001(\0132\r.conte" +
       "xt.Uuid\"=\n\017PolicyRuleState\022*\n\017policyRule" +
       "State\030\001 \001(\0162\021.policy.RuleState\"\225\002\n\017Polic" +
diff --git a/src/policy/target/generated-sources/grpc/policy/PolicyAction.java b/src/policy/target/generated-sources/grpc/policy/PolicyAction.java
index 1baaf538dc031be9443984f640826ccd893290e4..ea6ee17d03fecab1e341cdfbc97d5dd5f3b2576c 100644
--- a/src/policy/target/generated-sources/grpc/policy/PolicyAction.java
+++ b/src/policy/target/generated-sources/grpc/policy/PolicyAction.java
@@ -1,5 +1,5 @@
 // Generated by the protocol buffer compiler.  DO NOT EDIT!
-// source: policy-action.proto
+// source: policy_action.proto
 
 package policy;
 
@@ -907,7 +907,7 @@ public final class PolicyAction {
       descriptor;
   static {
     java.lang.String[] descriptorData = {
-      "\n\023policy-action.proto\022\006policy\"T\n\020PolicyR" +
+      "\n\023policy_action.proto\022\006policy\"T\n\020PolicyR" +
       "uleAction\022,\n\006action\030\001 \001(\0162\034.policy.Polic" +
       "yRuleActionEnum\022\022\n\nparameters\030\002 \003(\t*\274\001\n\024" +
       "PolicyRuleActionEnum\022\037\n\033POLICYRULE_ACTIO" +
diff --git a/src/policy/target/generated-sources/grpc/policy/PolicyCondition.java b/src/policy/target/generated-sources/grpc/policy/PolicyCondition.java
index 2bde987ea6b48fa4a5285775a235d26892ee3b81..ecd7192778b6f5e7d0f7ee8f189565c828860c21 100644
--- a/src/policy/target/generated-sources/grpc/policy/PolicyCondition.java
+++ b/src/policy/target/generated-sources/grpc/policy/PolicyCondition.java
@@ -1,5 +1,5 @@
 // Generated by the protocol buffer compiler.  DO NOT EDIT!
-// source: policy-condition.proto
+// source: policy_condition.proto
 
 package policy;
 
@@ -1325,7 +1325,7 @@ public final class PolicyCondition {
       descriptor;
   static {
     java.lang.String[] descriptorData = {
-      "\n\026policy-condition.proto\022\006policy\032\020monito" +
+      "\n\026policy_condition.proto\022\006policy\032\020monito" +
       "ring.proto\"\225\001\n\023PolicyRuleCondition\022 \n\005kp" +
       "iId\030\001 \001(\0132\021.monitoring.KpiId\0224\n\021numerica" +
       "lOperator\030\002 \001(\0162\031.policy.NumericalOperat" +
diff --git a/src/policy/target/kubernetes/kubernetes.yml b/src/policy/target/kubernetes/kubernetes.yml
index d70d05ad91cface20dd5ad1fc15ec1578a0767ca..b3313f771654e02f80bb7e4cadf68476afcadc75 100644
--- a/src/policy/target/kubernetes/kubernetes.yml
+++ b/src/policy/target/kubernetes/kubernetes.yml
@@ -3,20 +3,23 @@ apiVersion: v1
 kind: Service
 metadata:
   annotations:
-    app.quarkus.io/commit-id: 4a11d9130e05e969e9370636484943e1fe2f8bd1
-    app.quarkus.io/build-timestamp: 2022-07-27 - 12:54:10 +0000
+    app.quarkus.io/commit-id: a25756b932a3146d95a993cf529e26e48654455e
+    app.quarkus.io/build-timestamp: 2022-08-01 - 12:51:14 +0000
   labels:
     app.kubernetes.io/name: policyservice
     app: policyservice
   name: policyservice
 spec:
   ports:
-    - name: grpc
+    - name: grpc-server
       port: 6060
       targetPort: 6060
     - name: http
       port: 8080
       targetPort: 8080
+    - name: grpc
+      port: 6060
+      targetPort: 6060
   selector:
     app.kubernetes.io/name: policyservice
   type: ClusterIP
@@ -25,8 +28,8 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   annotations:
-    app.quarkus.io/commit-id: 4a11d9130e05e969e9370636484943e1fe2f8bd1
-    app.quarkus.io/build-timestamp: 2022-07-27 - 12:54:10 +0000
+    app.quarkus.io/commit-id: a25756b932a3146d95a993cf529e26e48654455e
+    app.quarkus.io/build-timestamp: 2022-08-01 - 12:51:14 +0000
   labels:
     app: policyservice
     app.kubernetes.io/name: policyservice
@@ -39,8 +42,8 @@ spec:
   template:
     metadata:
       annotations:
-        app.quarkus.io/commit-id: 4a11d9130e05e969e9370636484943e1fe2f8bd1
-        app.quarkus.io/build-timestamp: 2022-07-27 - 12:54:10 +0000
+        app.quarkus.io/commit-id: a25756b932a3146d95a993cf529e26e48654455e
+        app.quarkus.io/build-timestamp: 2022-08-01 - 12:51:14 +0000
       labels:
         app: policyservice
         app.kubernetes.io/name: policyservice
@@ -51,12 +54,12 @@ spec:
               valueFrom:
                 fieldRef:
                   fieldPath: metadata.namespace
-            - name: CONTEXT_SERVICE_HOST
-              value: contextservice
-            - name: SERVICE_SERVICE_HOST
-              value: serviceservice
             - name: MONITORING_SERVICE_HOST
               value: monitoringservice
+            - name: SERVICE_SERVICE_HOST
+              value: serviceservice
+            - name: CONTEXT_SERVICE_HOST
+              value: contextservice
           image: registry.gitlab.com/teraflow-h2020/controller/policy:0.1.0
           imagePullPolicy: Always
           livenessProbe:
@@ -72,11 +75,14 @@ spec:
           name: policyservice
           ports:
             - containerPort: 6060
-              name: grpc
+              name: grpc-server
               protocol: TCP
             - containerPort: 8080
               name: http
               protocol: TCP
+            - containerPort: 6060
+              name: grpc
+              protocol: TCP
           readinessProbe:
             failureThreshold: 3
             httpGet:
diff --git a/tutorial/3-0-development.md b/tutorial/3-0-development.md
index 0e2d1a03f21bbabcfeab46422b52903d2b5a53a7..c2b13315aec7ee506684a3b7cc2be40b9f6407fe 100644
--- a/tutorial/3-0-development.md
+++ b/tutorial/3-0-development.md
@@ -7,3 +7,4 @@ this guide assumes you are using the Oracle VirtualBox-based VM running MicroK8s
 ## Table of Content:
 - [3.1. Configure VSCode and Connect to the VM](./3-1-configure-vscode.md)
 - [3.2. Development Commands, Tricks, and Hints (WORK IN PROGRESS)](./3-2-develop-cth.md)
+- [3.3. Debugging individual components in VSCode](./3.3-debug-comp.md)
diff --git a/tutorial/3-1-configure-vscode.md b/tutorial/3-1-configure-vscode.md
index a2586142f1ca18897c25168c610fcecb0ea3ebcd..10493ce225d67043bcfcf9914905f19d270f060f 100644
--- a/tutorial/3-1-configure-vscode.md
+++ b/tutorial/3-1-configure-vscode.md
@@ -75,3 +75,18 @@ Host TFS-VM
 ```
   - Save the file
 - From now, VSCode will use the identity file to connect to the TFS-VM instead of the user's password.
+
+
+## 3.1.5. Install VSCode Python Extension (in VSCode server)
+This step installs Python extensions in VSCode server running in the VM.
+
+- In VSCode (connected to the VM), click left button "Extensions"
+- Search "Python" extension in the extension Marketplace.
+- Install official "Python" extension released by Microsoft.
+  - By default, since you're connected to the VM, it will be installed in the VSCode server running in the VM.
+
+- In VSCode (connected to the VM), click left button "Explorer"
+- Click "Ctrl+Alt+P" and type "Python: Select Interpreter". Select option "Python: 3.9.13 64-bit ('tfs')"
+
+in terminal: set python path to be used by VSCode:
+`echo "PYTHONPATH=./src" > ~/tfs-ctrl/.env`
diff --git a/tutorial/3-2-develop-cth.md b/tutorial/3-2-develop-cth.md
index 983e862d7c5e0ba06583739f797062ff9b9b32fc..eda70c9e8c411c8cc6a0ed0832f573ca787962ca 100644
--- a/tutorial/3-2-develop-cth.md
+++ b/tutorial/3-2-develop-cth.md
@@ -16,3 +16,22 @@ docker build -t "context:lgr-test" -f ./context/Dockerfile .
 
 Run by hand:
 docker run --rm --name lgr-test -it --env "DB_BACKEND=inmemory" --entrypoint /bin/bash context:lgr-test
+
+
+## Expose gRPC ports through Ingress Controller
+source `my_deploy.sh`
+run script `./expose_ingress_grpc.sh`
+
+to test:
+sudo apt-get install nmap
+nmap -p 1010 127.0.0.1  # test if context is reachable
+should retrieve something like:
+$ nmap -p 1010 127.0.0.1
+Starting Nmap 7.80 ( https://nmap.org ) at 2022-07-29 15:06 UTC
+Nmap scan report for localhost (127.0.0.1)
+Host is up (0.00035s latency).
+
+PORT     STATE SERVICE
+1010/tcp open  surf
+
+Nmap done: 1 IP address (1 host up) scanned in 0.07 seconds
diff --git a/tutorial/3.3-debug-comp.md b/tutorial/3.3-debug-comp.md
new file mode 100644
index 0000000000000000000000000000000000000000..380c5add26729c7d403135b20813b112ba214908
--- /dev/null
+++ b/tutorial/3.3-debug-comp.md
@@ -0,0 +1,55 @@
+# 3.3 Debugging individual components in VSCode
+
+## 3.3.1 Source TeraFlow environment variables into .bashrc
+
+With any text editor, open the file `~/.bashrc` and add the following line at the end:
+```bash
+source ~/tfs-ctrl/tfs_runtime_env_vars.sh
+```
+
+"tfs-ctrl" can be substituted by the appropriate path where the controller is deployed.
+
+## 3.3.2 Install VSCode Python extensions
+The following extensions are required to execute and debug TeraFlow components in VSCode:
+
+- *Python*. New versions of the extension are known to have some unsolved bugs, it is recommended to downgrade to version **v2022.10.0**. Go to the extension window, select Python, click the arrow next to the "Uninstall" button and select "Install Another Version..."
+- *Pylance*
+
+## 3.3.3 Configure VSCode workspace and launch settings
+Run VSCode and open the folder with the source code of TeraFlow, this will be the main workspace. Create (if it does not exist) the subfolder `.vscode`. Inside, create and edit the following files:
+
+- `settings.json` 
+    ```bash
+    {
+    "python.analysis.extraPaths": ["<HOME>/.pyenv/versions/3.9.7/envs/teraflow/lib/python3.9/site-packages"],
+    }
+    ```
+    `<HOME>` should be replaced by the path of your home folder. If in the future another version of Python is used, or the virtual environment changes, this file should be updated to reflect the new path of the installed pip packages.
+
+- `launch.json`
+    ```bash
+    {
+        // Use IntelliSense to learn about possible attributes.
+        // Hover to view descriptions of existing attributes.
+        // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+        "version": "0.2.0",
+        "configurations": [
+            {
+                "name": "TFS compute.service",
+                "module": "compute.service",
+                "python": "${command:python.interpreterPath}",
+                "type": "python",
+                "request": "launch",
+                "justMyCode": true,
+                "console": "internalConsole",
+                "env": {
+                    "PYTHONPATH": "${config:python.analysis.extraPaths}:${workspaceRoot}/src",
+                    "LOG_LEVEL": "DEBUG",
+                    }
+            }
+        ]
+    }
+    ```
+    This file contains the configuration necessary to execute the `"compute"` component from the TeraFlow controller, while providing debugging capabilities (e.g., breaking points, console log output etc.). After saving, the debugging can be started from the "Run and Debug" menu.
+
+    Additional profiles can be added to the JSON file under the `"configurations"` arrray. Copy & paste the existing one and change the `"name"` and  `"module"` fields.
\ No newline at end of file
diff --git a/update_tfs_runtime_env_vars.sh b/update_tfs_runtime_env_vars.sh
new file mode 100755
index 0000000000000000000000000000000000000000..db68e17ea49c035af085f2eb461f704b42c287e2
--- /dev/null
+++ b/update_tfs_runtime_env_vars.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+########################################################################################################################
+# Read deployment settings
+########################################################################################################################
+
+# If not already set, set the list of components you want to build images for, and deploy.
+# By default, only basic components are deployed
+export TFS_COMPONENTS=${TFS_COMPONENTS:-"context device monitoring service compute webui"}
+
+# If not already set, set the name of the Kubernetes namespace to deploy to.
+export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"}
+
+########################################################################################################################
+# Automated steps start here
+########################################################################################################################
+
+echo "Deploying components and collecting environment variables..."
+ENV_VARS_SCRIPT=tfs_runtime_env_vars.sh
+echo "# Environment variables for TeraFlowSDN deployment" > $ENV_VARS_SCRIPT
+PYTHONPATH=$(pwd)/src
+echo "export PYTHONPATH=${PYTHONPATH}" >> $ENV_VARS_SCRIPT
+
+for COMPONENT in $TFS_COMPONENTS; do
+    echo "  Collecting env-vars for '$COMPONENT' component..."
+
+    SERVICE_DATA=$(kubectl get service ${COMPONENT}service --namespace $TFS_K8S_NAMESPACE -o json)
+    if [ -z "${SERVICE_DATA}" ]; then continue; fi
+
+    # Env vars for service's host address
+    SERVICE_HOST=$(echo ${SERVICE_DATA} | jq -r '.spec.clusterIP')
+    if [ -z "${SERVICE_HOST}" ]; then continue; fi
+    ENVVAR_HOST=$(echo "${COMPONENT}service_SERVICE_HOST" | tr '[:lower:]' '[:upper:]')
+    echo "export ${ENVVAR_HOST}=${SERVICE_HOST}" >> $ENV_VARS_SCRIPT
+
+    # Env vars for service's 'grpc' port (if any)
+    SERVICE_PORT_GRPC=$(echo ${SERVICE_DATA} | jq -r '.spec.ports[] | select(.name=="grpc") | .port')
+    if [ -n "${SERVICE_PORT_GRPC}" ]; then
+        ENVVAR_PORT_GRPC=$(echo "${COMPONENT}service_SERVICE_PORT_GRPC" | tr '[:lower:]' '[:upper:]')
+        echo "export ${ENVVAR_PORT_GRPC}=${SERVICE_PORT_GRPC}" >> $ENV_VARS_SCRIPT
+    fi
+
+    # Env vars for service's 'http' port (if any)
+    SERVICE_PORT_HTTP=$(echo ${SERVICE_DATA} | jq -r '.spec.ports[] | select(.name=="http") | .port')
+    if [ -n "${SERVICE_PORT_HTTP}" ]; then
+        ENVVAR_PORT_HTTP=$(echo "${COMPONENT}service_SERVICE_PORT_HTTP" | tr '[:lower:]' '[:upper:]')
+        echo "export ${ENVVAR_PORT_HTTP}=${SERVICE_PORT_HTTP}" >> $ENV_VARS_SCRIPT
+    fi
+
+    printf "\n"
+done
+
+echo "Done!"