diff --git a/examples/extension_service/Dockerfile b/examples/extension_service/Dockerfile
index 9bb9a152b3343d3a48b5f07b511b528e2739955e..2c8ed85c1fe89a8792e59cd2999fe8ebb2f54d0a 100644
--- a/examples/extension_service/Dockerfile
+++ b/examples/extension_service/Dockerfile
@@ -11,7 +11,7 @@ ARG PIP_EXTRA_INDEX_URL=${PIP_EXTRA_INDEX_URL}
 ENV PIP_EXTRA_INDEX_URL=$PIP_EXTRA_INDEX_URL
 
 COPY . /home/${USER}/app
-RUN pip install perxis==0.0.16
+RUN pip install perxis==0.0.17
 
 ENV PYTHONPATH="/home/perx/app"
 ENV PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
diff --git a/examples/extension_service/Dockerfile.local b/examples/extension_service/Dockerfile.local
index 994d988a029b2c54363a269a7e55d0daff2f4da4..d8d0d31766a83b0069c695242665804a78e52890 100644
--- a/examples/extension_service/Dockerfile.local
+++ b/examples/extension_service/Dockerfile.local
@@ -11,7 +11,7 @@ ARG PIP_EXTRA_INDEX_URL=${PIP_EXTRA_INDEX_URL}
 ENV PIP_EXTRA_INDEX_URL=$PIP_EXTRA_INDEX_URL
 
 COPY . /home/${USER}/app
-RUN pip install perxis==0.0.16
+RUN pip install perxis==0.0.17
 RUN pip install 'watchdog[watchmedo]'
 
 ENV PYTHONPATH="/home/perx/app"
diff --git a/examples/extension_service/server.py b/examples/extension_service/server.py
index a4fb49cb79244b3f3bb8a01ef739f4a8e3361ad8..64bc3cf5ef3cb3bf21ed8d0175855932bbfb9ff5 100644
--- a/examples/extension_service/server.py
+++ b/examples/extension_service/server.py
@@ -18,7 +18,6 @@ def main():
     interceptor = header_adder_interceptor(
         'x-perxis-access', 'system'
     )
-
     with grpc.insecure_channel("extension-manager:9030") as extensions_manager_channel:
         intercept_channel_extensions_manager_channel = grpc.intercept_channel(extensions_manager_channel, interceptor)
 
diff --git a/perxis/extensions/extension_setup.py b/perxis/extensions/extension_setup.py
index 6f42a6261c44f98210dc80d7c5cc1243d95fb20c..a93e6fc64147bb8dd2c97309e8dec736c3ca6d3f 100644
--- a/perxis/extensions/extension_setup.py
+++ b/perxis/extensions/extension_setup.py
@@ -8,6 +8,7 @@ import typing
 from deepdiff import DeepDiff
 from perxis.collections import collections_pb2_grpc, collections_pb2
 from perxis.roles import roles_pb2_grpc, roles_pb2
+from perxis.common import common_pb2
 from perxis.clients import clients_pb2_grpc, clients_pb2
 from perxis.environments import environments_pb2_grpc, environments_pb2
 
@@ -81,43 +82,82 @@ class ExtensionSetup:
 
         return errors_list
 
-    def __update_roles(self, space_id: str) -> list[str]:
+    def __update_roles(self, space_id: str, env_id: str) -> list[str]:
         errors_list = []
 
         for local_role in self.roles:
             try:
-                cloned_role = copy.deepcopy(local_role)
-                cloned_role.space_id = space_id
-
-                # Полностью замещать данные роли тем что имеется в расширении
-                # TODO: нужно ли мержить права чтобы не терять изменения?
-                self.roles_service.Update.with_call(
-                    roles_pb2.UpdateRequest(
-                        role=cloned_role
+                get_response, state = self.roles_service.Get.with_call(
+                    roles_pb2.GetRequest(
+                        space_id=space_id,
+                        role_id=local_role.id
                     )
                 )
+
+                role = get_response.role
             except grpc.RpcError as e:
-                errors_list.append(f"Не удалось обновить роль {local_role.id}, {e.details()}")
+                if "not found" not in e.details():
+                    errors_list.append(f"Не удалось получить роль {local_role.id}, {e.details()}")
+                    continue
 
-        return errors_list
+                role = None
 
-    def __create_roles(self, space_id: str) -> list[str]:
-        errors_list = []
+            cloned_role = copy.deepcopy(local_role)
+            cloned_role.space_id = space_id
 
-        for local_role in self.roles:
-            try:
-                cloned_role = copy.deepcopy(local_role)
-                cloned_role.space_id = space_id
+            if role:
+                if not role.environments:
+                    role.environments[:] = [env_id]
+                elif env_id not in role.environments:
+                    role.environments.append(env_id)
 
-                response, _ = self.roles_service.Create.with_call(
-                    roles_pb2.CreateRequest(
-                        role=cloned_role
-                    ),
-                )
-            except grpc.RpcError as e:
-                # На этапе install считается что ролей __нет__. При install с указанием force роли предварительно
-                # удаляются
-                errors_list.append(f"Не удалось создать роль {local_role.id}, {e.details()}")
+                cloned_role.environments[:] = role.environments
+
+                # Произвести мерж правил доступа
+                for exist_rule in role.rules:
+                    was_found = False
+
+                    for local_rule in cloned_role.rules:
+                        # Если запись с правами доступа на коллекцию найдена - правила нужно совместить
+                        if local_rule.collection_id == exist_rule.collection_id:
+                            was_found = True
+
+                            local_rule.actions[:] = list(set(list(local_rule.actions) + list(exist_rule.actions)))
+
+                            break
+
+                    # Если правило для коллекций не было найдено - его нужно добавить
+                    if not was_found:
+                        cloned_role.rules.append(common_pb2.Rule(
+                            collection_id=exist_rule.collection_id,
+                            actions=list(exist_rule.actions)
+                        ))
+
+                try:
+                    self.roles_service.Update.with_call(
+                        roles_pb2.UpdateRequest(
+                            role=cloned_role
+                        )
+                    )
+                except grpc.RpcError as e:
+                    errors_list.append(f"Не удалось обновить роль {local_role.id}, {e.details()}")
+            else:
+                if env_id not in cloned_role.environments:
+                    cloned_role.environments.append(env_id)
+
+                try:
+                    cloned_role = copy.deepcopy(local_role)
+                    cloned_role.space_id = space_id
+
+                    response, _ = self.roles_service.Create.with_call(
+                        roles_pb2.CreateRequest(
+                            role=cloned_role
+                        ),
+                    )
+                except grpc.RpcError as e:
+                    # На этапе install считается что ролей __нет__. При install с указанием force роли предварительно
+                    # удаляются
+                    errors_list.append(f"Не удалось создать роль {local_role.id}, {e.details()}")
 
         return errors_list
 
@@ -169,51 +209,47 @@ class ExtensionSetup:
 
                 client = get_response.client
             except grpc.RpcError as e:
-                errors_list.append(f"Не удалось получить клиент {local_client.id}, {e.details()}")
-
-                continue
+                if "not found" not in e.details():
+                    errors_list.append(f"Не удалось получить клиент {local_client.id}, {e.details()}")
+                    continue
 
-            try:
-                # Нужно чтобы у клиента каждый раз не слетали данные токенов при переустановке
-                # свойства oauth, api_key и tls должны браться из __созданного__ клиента
-                new_client = clients_pb2.Client(
-                    id=local_client.id,
-                    space_id=space_id,
-                    name=local_client.name,
-                    description=local_client.description,
-                    disabled=client.disabled,
-                    role_id=local_client.role_id,
-                    oauth=client.oauth,
-                    api_key=client.api_key,
-                    tls=client.tls
-                )
+                client = None
 
-                self.clients_service.Update.with_call(
-                    clients_pb2.UpdateRequest(
-                        client=new_client
+            if client:
+                try:
+                    # Нужно чтобы у клиента каждый раз не слетали данные токенов при переустановке
+                    # свойства oauth, api_key и tls должны браться из __созданного__ клиента
+                    new_client = clients_pb2.Client(
+                        id=local_client.id,
+                        space_id=space_id,
+                        name=local_client.name,
+                        description=local_client.description,
+                        disabled=client.disabled,
+                        role_id=local_client.role_id,
+                        oauth=client.oauth or local_client.oauth,
+                        api_key=client.api_key or local_client.api_key,
+                        tls=client.tls
                     )
-                )
-            except grpc.RpcError as e:
-                errors_list.append(f"Не удалось обновить клиент {local_client.id}, {e.details()}")
-
-        return errors_list
-
-    def __create_clients(self, space_id: str) -> list[str]:
-        errors_list = []
 
-        for local_client in self.clients:
-            try:
-                cloned_client = copy.deepcopy(local_client)
-                cloned_client.space_id = space_id
+                    self.clients_service.Update.with_call(
+                        clients_pb2.UpdateRequest(
+                            client=new_client
+                        )
+                    )
+                except grpc.RpcError as e:
+                    errors_list.append(f"Не удалось обновить клиент {local_client.id}, {e.details()}")
+            else:
+                try:
+                    cloned_client = copy.deepcopy(local_client)
+                    cloned_client.space_id = space_id
 
-                response, _ = self.clients_service.Create.with_call(
-                    clients_pb2.CreateRequest(
-                        client=cloned_client
-                    ),
-                )
-            except grpc.RpcError as e:
-                # Как и с ролями считается что при install записей быть не должно в любом случае т.к. force всё удаляет
-                errors_list.append(f"Не удалось создать клиент {local_client.id}, {e.details()}")
+                    response, _ = self.clients_service.Create.with_call(
+                        clients_pb2.CreateRequest(
+                            client=cloned_client
+                        ),
+                    )
+                except grpc.RpcError as e:
+                    errors_list.append(f"Не удалось создать клиент {local_client.id}, {e.details()}")
 
         return errors_list
 
@@ -389,40 +425,6 @@ class ExtensionSetup:
 
         return error_message
 
-    def __create_collections(self, space_id: str, env_id: str) -> list[str]:
-        errors_list = []
-
-        for local_collection in self.collections:
-            try:
-                cloned_collection = copy.deepcopy(local_collection)
-                cloned_collection.space_id = space_id
-                cloned_collection.env_id = env_id
-
-                response, _ = self.collections_service.Create.with_call(
-                    collections_pb2.CreateRequest(
-                        collection=cloned_collection
-                    ),
-                )
-            except grpc.RpcError as e:
-                errors_list.append(f"Не удалось создать коллекцию {local_collection.id}, {e.details()}")
-
-                # Если коллекцию создать не удалось (по любой причине) дальнейшая обработка коллекции смысла
-                # не имеет
-                continue
-
-            set_schema_error_message = self.__set_collection_schema(
-                space_id, env_id, local_collection.id, local_collection.schema
-            )
-            if set_schema_error_message:
-                errors_list.append(set_schema_error_message)
-
-        # Миграция окружения нужна в любом случае т.к. все коллекции были __созданы__
-        migrate_environment_error_message = self.__migrate_environment(space_id, env_id)
-        if migrate_environment_error_message:
-            errors_list.append(migrate_environment_error_message)
-
-        return errors_list
-
     def install(self, space_id: str, env_id: str, use_force: bool) -> list[str]:
         errors = []
 
@@ -431,9 +433,9 @@ class ExtensionSetup:
             errors += self.__remove_clients(space_id)
             errors += self.__remove_roles(space_id)
 
-        errors += self.__create_collections(space_id, env_id)
-        errors += self.__create_roles(space_id)
-        errors += self.__create_clients(space_id)
+        errors += self.__update_collections(space_id, env_id)
+        errors += self.__update_roles(space_id, env_id)
+        errors += self.__update_clients(space_id)
 
         return errors
 
@@ -441,19 +443,14 @@ class ExtensionSetup:
         errors = []
 
         # В случае обновление расширения с флагом force нужно предварительно удалить все сущности.
-        # Фактически это переустановка а не удаление
         if use_force:
             errors += self.__remove_clients(space_id)
             errors += self.__remove_roles(space_id)
             errors += self.__remove_collections(space_id, env_id)
 
-            errors += self.__create_collections(space_id, env_id)
-            errors += self.__create_roles(space_id)
-            errors += self.__create_clients(space_id)
-        else:
-            errors += self.__update_collections(space_id, env_id)
-            errors += self.__update_roles(space_id)
-            errors += self.__update_clients(space_id)
+        errors += self.__update_collections(space_id, env_id)
+        errors += self.__update_roles(space_id, env_id)
+        errors += self.__update_clients(space_id)
 
         return errors
 
diff --git a/setup.py b/setup.py
index 1781eb7ca03cd21aa2036a67d541c2998393e190..97684b0a88e9b10112224c6939f5ac6d5ad724c9 100644
--- a/setup.py
+++ b/setup.py
@@ -14,7 +14,7 @@ def load_requirements():
 
 setup(
     name='perxis',
-    version='0.0.16',
+    version='0.0.17',
     description='Perxis python client',
     long_description=long_description,
     long_description_content_type='text/markdown',