diff --git a/plugins/activity-resources/src/activityMessagesUtils.ts b/plugins/activity-resources/src/activityMessagesUtils.ts
index 9fbcd5815e..c9287c59aa 100644
--- a/plugins/activity-resources/src/activityMessagesUtils.ts
+++ b/plugins/activity-resources/src/activityMessagesUtils.ts
@@ -21,6 +21,7 @@ import core, {
   type Doc,
   groupByArray,
   type Hierarchy,
+  type Mixin,
   type Ref,
   SortingOrder,
   type Timestamp
@@ -70,7 +71,13 @@ export async function getAttributeValues (client: Client, values: any[], attrCla
   const docIds = docs.map(({ _id }) => _id)
   const missedIds = values.filter((value) => !docIds.includes(value))
   const removedDocs = await Promise.all(missedIds.map(async (value) => await buildRemovedDoc(client, value, attrClass)))
-  return [...docs, ...removedDocs].filter((doc) => !(doc == null))
+  const allDocs = [...docs, ...removedDocs].filter((doc) => !(doc == null))
+
+  if (allDocs.length > 0) {
+    return allDocs
+  }
+
+  return values
 }
 
 export function getCollectionAttribute (
@@ -94,6 +101,19 @@ export function getCollectionAttribute (
   return undefined
 }
 
+async function getAttributePresenterSafe (
+  client: Client,
+  _class: Ref<Class<Doc>>,
+  attrKey: string,
+  mixin?: Ref<Mixin<Doc>>
+): Promise<AttributeModel | undefined> {
+  try {
+    return await getAttributePresenter(client, _class, attrKey, { key: attrKey }, mixin)
+  } catch (e) {
+    console.error(e)
+  }
+}
+
 export async function getAttributeModel (
   client: Client,
   attributeUpdates: DocAttributeUpdates | undefined,
@@ -105,28 +125,24 @@ export async function getAttributeModel (
 
   const hierarchy = client.getHierarchy()
 
-  try {
-    const { attrKey, attrClass, isMixin } = attributeUpdates
-    let attrObjectClass = objectClass
+  const { attrKey, attrClass, isMixin } = attributeUpdates
+  let attrObjectClass = objectClass
 
-    if (isMixin) {
-      const keyedAttribute = getFiltredKeys(hierarchy, attrClass, []).find(({ key }) => key === attrKey)
-      if (keyedAttribute === undefined) {
-        return undefined
-      }
-      attrObjectClass = keyedAttribute.attr.attributeOf
+  if (isMixin) {
+    const keyedAttribute = getFiltredKeys(hierarchy, attrClass, []).find(({ key }) => key === attrKey)
+    if (keyedAttribute === undefined) {
+      return undefined
     }
-
-    return await getAttributePresenter(
-      client,
-      attrObjectClass,
-      attrKey,
-      { key: attrKey },
-      view.mixin.ActivityAttributePresenter
-    )
-  } catch (e) {
-    // ignore error
+    attrObjectClass = keyedAttribute.attr.attributeOf
   }
+
+  const model = await getAttributePresenterSafe(client, attrObjectClass, attrKey, view.mixin.ActivityAttributePresenter)
+
+  if (model !== undefined) {
+    return model
+  }
+
+  return await getAttributePresenterSafe(client, attrObjectClass, attrKey)
 }
 
 export function activityMessagesComparator (message1: ActivityMessage, message2: ActivityMessage): number {
diff --git a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageContent.svelte b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageContent.svelte
index cc17e09bca..deb12f2b0e 100644
--- a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageContent.svelte
+++ b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageContent.svelte
@@ -26,16 +26,12 @@
   export let viewlet: DocUpdateMessageViewlet | undefined
   export let objectName: IntlString
   export let collectionName: IntlString | undefined
-  export let objectClass: Ref<Class<Doc>>
   export let collectionAttribute: Attribute<Collection<AttachedDoc>> | undefined = undefined
 
   const client = getClient()
   const hierarchy = client.getHierarchy()
   const clazz = hierarchy.getClass(message.objectClass)
 
-  const objectPanel = hierarchy.classHierarchyMixin(objectClass, view.mixin.ObjectPanel)
-  const objectPresenter = hierarchy.classHierarchyMixin(objectClass, view.mixin.ObjectPresenter)
-
   const isOwn = message.objectId === message.attachedTo
 
   let valueMessages: DocUpdateMessage[] = []
@@ -71,8 +67,6 @@
     {#each createMessages as valueMessage, index}
       <DocUpdateMessageObjectValue
         message={valueMessage}
-        {objectPresenter}
-        {objectPanel}
         {viewlet}
         withIcon={index === 0}
         hasSeparator={createMessages.length > 1 && index !== createMessages.length - 1}
@@ -81,8 +75,6 @@
     {#each removeMessages as valueMessage, index}
       <DocUpdateMessageObjectValue
         message={valueMessage}
-        {objectPresenter}
-        {objectPanel}
         {viewlet}
         withIcon={index === 0}
         hasSeparator={removeMessages.length > 1 && index !== removeMessages.length - 1}
@@ -92,8 +84,6 @@
     {#each valueMessages as valueMessage, index}
       <DocUpdateMessageObjectValue
         message={valueMessage}
-        {objectPresenter}
-        {objectPanel}
         {viewlet}
         hasSeparator={valueMessages.length > 1 && index !== valueMessages.length - 1}
       />
diff --git a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageObjectValue.svelte b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageObjectValue.svelte
index d8f23e3402..60332226dc 100644
--- a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageObjectValue.svelte
+++ b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageObjectValue.svelte
@@ -22,16 +22,18 @@
 
   export let message: DisplayDocUpdateMessage
   export let viewlet: DocUpdateMessageViewlet | undefined
-  export let objectPanel: ObjectPanel | undefined
-  export let objectPresenter: ObjectPresenter | undefined
   export let withIcon: boolean = false
   export let hasSeparator: boolean = false
 
   const client = getClient()
+  const hierarchy = client.getHierarchy()
   const objectQuery = createQuery()
 
   let object: Doc | undefined = undefined
 
+  $: objectPanel = hierarchy.classHierarchyMixin(message.objectClass, view.mixin.ObjectPanel)
+  $: objectPresenter = hierarchy.classHierarchyMixin(message.objectClass, view.mixin.ObjectPresenter)
+
   async function getValue (object: Doc): Promise<string | undefined> {
     if (viewlet?.valueAttr) {
       return (object as any)[viewlet.valueAttr]
diff --git a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte
index 916fd1adb2..b1f7ac66ff 100644
--- a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte
+++ b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte
@@ -83,7 +83,7 @@
     .getModel()
     .findAllSync(activity.class.DocUpdateMessageViewlet, { action: value.action, objectClass: value.objectClass })
 
-  $: void getAttributeModel(client, value.attributeUpdates, value.attachedToClass).then((model) => {
+  $: void getAttributeModel(client, value.attributeUpdates, value.objectClass).then((model) => {
     attributeModel = model
   })
 
@@ -197,14 +197,7 @@
         </ShowMore>
       {:else if value.action === 'create' || value.action === 'remove'}
         <ShowMore>
-          <DocUpdateMessageContent
-            objectClass={value.objectClass}
-            message={value}
-            {viewlet}
-            {objectName}
-            {collectionName}
-            {collectionAttribute}
-          />
+          <DocUpdateMessageContent message={value} {viewlet} {objectName} {collectionName} {collectionAttribute} />
         </ShowMore>
       {:else if value.attributeUpdates && attributeModel}
         <DocUpdateMessageAttributes attributeUpdates={value.attributeUpdates} {attributeModel} {viewlet} />
diff --git a/server-plugins/activity-resources/src/index.ts b/server-plugins/activity-resources/src/index.ts
index 7c77b31bd5..d8c73de9d2 100644
--- a/server-plugins/activity-resources/src/index.ts
+++ b/server-plugins/activity-resources/src/index.ts
@@ -186,7 +186,7 @@ async function pushDocUpdateMessages (
     )
   }
 
-  if (attributesUpdates.length === 0) {
+  if (attributesUpdates.length === 0 && rawMessage.action !== 'update') {
     res.push(getDocUpdateMessageTx(control, originTx, object, rawMessage, modifiedBy))
   }
 
@@ -254,14 +254,12 @@ export async function generateDocUpdateMessages (
     case core.class.TxCollectionCUD: {
       const actualTx = TxProcessor.extractTx(tx) as TxCUD<Doc>
       res = await generateDocUpdateMessages(actualTx, control, res, tx, objectCache)
-      if ([core.class.TxCreateDoc, core.class.TxRemoveDoc].includes(actualTx._class)) {
+      if ([core.class.TxCreateDoc, core.class.TxRemoveDoc, core.class.TxUpdateDoc].includes(actualTx._class)) {
         let doc = objectCache?.docs?.get(tx.objectId)
         if (doc === undefined) {
           doc = (await control.findAll(tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0]
         }
-        if (doc !== undefined) {
-          return await pushDocUpdateMessages(control, res, doc ?? undefined, originTx ?? tx, undefined, objectCache)
-        }
+        return await pushDocUpdateMessages(control, res, doc ?? undefined, originTx ?? tx, undefined, objectCache)
       }
       return res
     }
diff --git a/server-plugins/activity-resources/src/utils.ts b/server-plugins/activity-resources/src/utils.ts
index 18123fc43d..31c2e67920 100644
--- a/server-plugins/activity-resources/src/utils.ts
+++ b/server-plugins/activity-resources/src/utils.ts
@@ -189,6 +189,17 @@ export async function getTxAttributesUpdates (
     return []
   }
 
+  let updateObject = object
+
+  if (updateObject._id !== tx.objectId) {
+    updateObject =
+      objectCache?.docs?.get(tx.objectId) ?? (await control.findAll(tx.objectClass, { _id: tx.objectId }))[0]
+  }
+
+  if (updateObject === undefined) {
+    return []
+  }
+
   const hierarchy = control.hierarchy
   const keys = getAvailableAttributesKeys(tx, hierarchy)
 
@@ -201,7 +212,14 @@ export async function getTxAttributesUpdates (
   const isMixin = hierarchy.isDerived(tx._class, core.class.TxMixin)
   const mixin = isMixin ? (tx as TxMixin<Doc, Doc>).mixin : undefined
 
-  const { doc, prevDoc } = await getDocDiff(control, object._class, object._id, originTx._id, mixin, objectCache)
+  const { doc, prevDoc } = await getDocDiff(
+    control,
+    updateObject._class,
+    updateObject._id,
+    originTx._id,
+    mixin,
+    objectCache
+  )
 
   for (const key of keys) {
     let attrValue = modifiedAttributes[key]
@@ -212,7 +230,7 @@ export async function getTxAttributesUpdates (
 
     let attrClass: Ref<Class<Doc>> | undefined = mixin
 
-    const clazz = hierarchy.findAttribute(object._class, key)
+    const clazz = hierarchy.findAttribute(updateObject._class, key)
 
     if (clazz !== undefined && 'to' in clazz.type) {
       attrClass = clazz.type.to as Ref<Class<Doc>>
@@ -247,10 +265,18 @@ export async function getTxAttributesUpdates (
       }
     }
 
+    let setAttr = []
+
+    if (Array.isArray(attrValue)) {
+      setAttr = attrValue
+    } else if (key in modifiedAttributes) {
+      setAttr = [attrValue]
+    }
+
     result.push({
       attrKey: key,
       attrClass,
-      set: Array.isArray(attrValue) ? attrValue : [attrValue],
+      set: setAttr,
       added,
       removed,
       prevValue,
diff --git a/server-plugins/notification-resources/src/index.ts b/server-plugins/notification-resources/src/index.ts
index 439b990cc8..0e92b28fd9 100644
--- a/server-plugins/notification-resources/src/index.ts
+++ b/server-plugins/notification-resources/src/index.ts
@@ -748,7 +748,7 @@ async function collectionCollabDoc (
   const actualTx = TxProcessor.extractTx(tx) as TxCUD<Doc>
   let res = await createCollaboratorNotifications(actualTx, control, activityMessages, tx)
 
-  if (![core.class.TxCreateDoc, core.class.TxRemoveDoc].includes(actualTx._class)) {
+  if (![core.class.TxCreateDoc, core.class.TxRemoveDoc, core.class.TxUpdateDoc].includes(actualTx._class)) {
     return res
   }