diff --git a/models/activity/package.json b/models/activity/package.json
index 00d35887ac..71570dd350 100644
--- a/models/activity/package.json
+++ b/models/activity/package.json
@@ -35,6 +35,7 @@
     "@hcengineering/model": "^0.6.11",
     "@hcengineering/model-core": "^0.6.0",
     "@hcengineering/model-preference": "^0.6.0",
+    "@hcengineering/model-presentation": "^0.6.0",
     "@hcengineering/model-view": "^0.6.0",
     "@hcengineering/notification": "^0.6.23",
     "@hcengineering/platform": "^0.6.11",
diff --git a/models/activity/src/index.ts b/models/activity/src/index.ts
index c14f33b646..6d63a993c0 100644
--- a/models/activity/src/index.ts
+++ b/models/activity/src/index.ts
@@ -70,6 +70,7 @@ import preference, { TPreference } from '@hcengineering/model-preference'
 import view from '@hcengineering/model-view'
 import type { Asset, IntlString, Resource } from '@hcengineering/platform'
 import { type AnyComponent } from '@hcengineering/ui/src/types'
+import presentation from '@hcengineering/model-presentation'
 
 import activity from './plugin'
 import { buildActions } from './actions'
@@ -375,6 +376,10 @@ export function createModel (builder: Builder): void {
     ]
   })
 
+  builder.mixin(activity.class.Reaction, core.class.Class, presentation.mixin.InstantTransactions, {
+    txClasses: [core.class.TxCreateDoc]
+  })
+
   buildActions(builder)
   buildNotifications(builder)
 }
diff --git a/packages/core/src/operations.ts b/packages/core/src/operations.ts
index 5dd2c35e4c..9db10bdae0 100644
--- a/packages/core/src/operations.ts
+++ b/packages/core/src/operations.ts
@@ -98,7 +98,7 @@ export class TxOperations implements Omit<Client, 'notify'> {
       throw new Error('createDoc cannot be called for DOMAIN_MODEL classes with non-model space')
     }
     const tx = this.txFactory.createTxCreateDoc(_class, space, attributes, id, modifiedOn, modifiedBy)
-    await this.client.tx(tx)
+    await this.tx(tx)
     return tx.objectId
   }
 
@@ -122,7 +122,7 @@ export class TxOperations implements Omit<Client, 'notify'> {
       modifiedOn,
       modifiedBy
     )
-    await this.client.tx(tx)
+    await this.tx(tx)
     return tx.tx.objectId as unknown as Ref<P>
   }
 
@@ -147,7 +147,7 @@ export class TxOperations implements Omit<Client, 'notify'> {
       modifiedOn,
       modifiedBy
     )
-    await this.client.tx(tx)
+    await this.tx(tx)
     return tx.objectId
   }
 
@@ -170,7 +170,7 @@ export class TxOperations implements Omit<Client, 'notify'> {
       modifiedOn,
       modifiedBy
     )
-    await this.client.tx(tx)
+    await this.tx(tx)
     return tx.objectId
   }
 
@@ -184,7 +184,7 @@ export class TxOperations implements Omit<Client, 'notify'> {
     modifiedBy?: Ref<Account>
   ): Promise<TxResult> {
     const tx = this.txFactory.createTxUpdateDoc(_class, space, objectId, operations, retrieve, modifiedOn, modifiedBy)
-    return this.client.tx(tx)
+    return this.tx(tx)
   }
 
   removeDoc<T extends Doc>(
@@ -195,7 +195,7 @@ export class TxOperations implements Omit<Client, 'notify'> {
     modifiedBy?: Ref<Account>
   ): Promise<TxResult> {
     const tx = this.txFactory.createTxRemoveDoc(_class, space, objectId, modifiedOn, modifiedBy)
-    return this.client.tx(tx)
+    return this.tx(tx)
   }
 
   createMixin<D extends Doc, M extends D>(
@@ -216,7 +216,7 @@ export class TxOperations implements Omit<Client, 'notify'> {
       modifiedOn,
       modifiedBy
     )
-    return this.client.tx(tx)
+    return this.tx(tx)
   }
 
   updateMixin<D extends Doc, M extends D>(
@@ -237,7 +237,7 @@ export class TxOperations implements Omit<Client, 'notify'> {
       modifiedOn,
       modifiedBy
     )
-    return this.client.tx(tx)
+    return this.tx(tx)
   }
 
   async update<T extends Doc>(
diff --git a/packages/ui/src/utils.ts b/packages/ui/src/utils.ts
index fb056b68bc..e769f24194 100644
--- a/packages/ui/src/utils.ts
+++ b/packages/ui/src/utils.ts
@@ -111,7 +111,7 @@ export function addNotification (
     title,
     subTitle,
     severity,
-    position: NotificationPosition.TopRight,
+    position: NotificationPosition.BottomLeft,
     component,
     closeTimeout,
     params
diff --git a/plugins/activity-resources/src/components/Activity.svelte b/plugins/activity-resources/src/components/Activity.svelte
index 9fea4555e9..5a2cc7db4f 100644
--- a/plugins/activity-resources/src/components/Activity.svelte
+++ b/plugins/activity-resources/src/components/Activity.svelte
@@ -211,6 +211,11 @@
       {
         sort: {
           createdOn: SortingOrder.Ascending
+        },
+        lookup: {
+          _id: {
+            reactions: activity.class.Reaction
+          }
         }
       }
     )
diff --git a/plugins/activity-resources/src/components/ActivityMessageActions.svelte b/plugins/activity-resources/src/components/ActivityMessageActions.svelte
index 62129d1bf8..5a28faa06e 100644
--- a/plugins/activity-resources/src/components/ActivityMessageActions.svelte
+++ b/plugins/activity-resources/src/components/ActivityMessageActions.svelte
@@ -39,7 +39,7 @@
   $: void updateInlineActions(message, excludedActions)
 
   savedMessagesStore.subscribe(() => {
-    void updateInlineActions(message)
+    void updateInlineActions(message, excludedActions)
   })
 
   function handleActionMenuOpened (): void {
diff --git a/plugins/activity-resources/src/components/doc-update-message/attributes/SetAttributesPresenter.svelte b/plugins/activity-resources/src/components/doc-update-message/attributes/SetAttributesPresenter.svelte
index 605c857b63..e50a586b7a 100644
--- a/plugins/activity-resources/src/components/doc-update-message/attributes/SetAttributesPresenter.svelte
+++ b/plugins/activity-resources/src/components/doc-update-message/attributes/SetAttributesPresenter.svelte
@@ -69,6 +69,7 @@
         attribute={attributeModel.attribute}
         value={values[0]}
         {prevValue}
+        withShowMore={false}
         showOnlyDiff
       />
     {/if}
diff --git a/plugins/activity-resources/src/components/reactions/Reactions.svelte b/plugins/activity-resources/src/components/reactions/Reactions.svelte
index 7df064d594..440cb291ba 100644
--- a/plugins/activity-resources/src/components/reactions/Reactions.svelte
+++ b/plugins/activity-resources/src/components/reactions/Reactions.svelte
@@ -55,7 +55,7 @@
     ev.preventDefault()
     ev.stopPropagation()
     showPopup(EmojiPopup, {}, ev.target as HTMLElement, async (emoji: string) => {
-      await updateDocReactions(client, reactions, object, emoji)
+      await updateDocReactions(reactions, object, emoji)
     })
   }
 </script>
diff --git a/plugins/activity-resources/src/components/reactions/ReactionsPresenter.svelte b/plugins/activity-resources/src/components/reactions/ReactionsPresenter.svelte
index a495545053..86eb49e3a1 100644
--- a/plugins/activity-resources/src/components/reactions/ReactionsPresenter.svelte
+++ b/plugins/activity-resources/src/components/reactions/ReactionsPresenter.svelte
@@ -14,40 +14,48 @@
 -->
 <script lang="ts">
   import activity, { ActivityMessage, Reaction } from '@hcengineering/activity'
-  import { createQuery, getClient } from '@hcengineering/presentation'
+  import { createQuery } from '@hcengineering/presentation'
+  import { WithLookup } from '@hcengineering/core'
 
   import { getSpace, updateDocReactions } from '../../utils'
   import Reactions from './Reactions.svelte'
 
-  export let object: ActivityMessage | undefined
+  export let object: WithLookup<ActivityMessage> | undefined
   export let readonly = false
 
-  const client = getClient()
   const reactionsQuery = createQuery()
 
   let reactions: Reaction[] = []
 
-  $: hasReactions = object?.reactions && object.reactions > 0
+  $: hasReactions = (object?.reactions ?? 0) > 0
+  $: lookupReactions = object?.$lookup?.reactions as Reaction[] | undefined
 
-  $: if (object && hasReactions) {
-    reactionsQuery.query(
-      activity.class.Reaction,
-      { attachedTo: object._id, space: getSpace(object) },
-      (res: Reaction[]) => {
-        reactions = res
-      }
-    )
-  } else {
-    reactionsQuery.unsubscribe()
+  $: updateReactions(hasReactions, object, lookupReactions)
+
+  function updateReactions (hasReactions: boolean, object?: ActivityMessage, lookupReaction?: Reaction[]): void {
+    if (lookupReaction !== undefined) {
+      reactions = lookupReaction
+    } else if (object && hasReactions) {
+      reactionsQuery.query(
+        activity.class.Reaction,
+        { attachedTo: object._id, space: getSpace(object) },
+        (res: Reaction[]) => {
+          reactions = res
+        }
+      )
+    } else {
+      reactionsQuery.unsubscribe()
+      reactions = []
+    }
   }
 
   const handleClick = (ev: CustomEvent) => {
     if (readonly) return
-    void updateDocReactions(client, reactions, object, ev.detail)
+    void updateDocReactions(reactions, object, ev.detail)
   }
 </script>
 
-{#if object && hasReactions}
+{#if object && reactions.length > 0}
   <div class="footer flex-col p-inline contrast mt-2 min-h-6">
     <Reactions {reactions} {object} {readonly} on:click={handleClick} />
   </div>
diff --git a/plugins/activity-resources/src/components/reactions/ReactionsPreview.svelte b/plugins/activity-resources/src/components/reactions/ReactionsPreview.svelte
index 9e5f5374c0..917e11a97a 100644
--- a/plugins/activity-resources/src/components/reactions/ReactionsPreview.svelte
+++ b/plugins/activity-resources/src/components/reactions/ReactionsPreview.svelte
@@ -66,7 +66,7 @@
     e.stopPropagation()
     e.preventDefault()
     showPopup(EmojiPopup, {}, e.target as HTMLElement, (emoji: string) => {
-      void updateDocReactions(client, reactions, message, emoji)
+      void updateDocReactions(reactions, message, emoji)
     })
   }
 </script>
diff --git a/plugins/activity-resources/src/utils.ts b/plugins/activity-resources/src/utils.ts
index 7a91bb20bb..06df26ee33 100644
--- a/plugins/activity-resources/src/utils.ts
+++ b/plugins/activity-resources/src/utils.ts
@@ -1,12 +1,5 @@
 import type { ActivityMessage, Reaction } from '@hcengineering/activity'
-import core, {
-  getCurrentAccount,
-  isOtherHour,
-  type Doc,
-  type Ref,
-  type TxOperations,
-  type Space
-} from '@hcengineering/core'
+import core, { getCurrentAccount, isOtherHour, type Doc, type Ref, type Space } from '@hcengineering/core'
 import { getClient, isSpace } from '@hcengineering/presentation'
 import {
   EmojiPopup,
@@ -22,18 +15,13 @@ import { get } from 'svelte/store'
 import { savedMessagesStore } from './activity'
 import activity from './plugin'
 
-export async function updateDocReactions (
-  client: TxOperations,
-  reactions: Reaction[],
-  object?: Doc,
-  emoji?: string
-): Promise<void> {
+export async function updateDocReactions (reactions: Reaction[], object?: Doc, emoji?: string): Promise<void> {
   if (emoji === undefined || object === undefined) {
     return
   }
 
+  const client = getClient()
   const currentAccount = getCurrentAccount()
-
   const reaction = reactions.find((r) => r.emoji === emoji && r.createBy === currentAccount._id)
 
   if (reaction == null) {
@@ -72,7 +60,7 @@ export async function addReactionAction (
   closePopup()
 
   showPopup(EmojiPopup, {}, element, (emoji: string) => {
-    void updateDocReactions(client, reactions, message, emoji)
+    void updateDocReactions(reactions, message, emoji)
     params?.onClose?.()
   })
   params?.onOpen?.()
diff --git a/plugins/chunter-resources/src/channelDataProvider.ts b/plugins/chunter-resources/src/channelDataProvider.ts
index 66244cb07d..c095d0e855 100644
--- a/plugins/chunter-resources/src/channelDataProvider.ts
+++ b/plugins/chunter-resources/src/channelDataProvider.ts
@@ -20,6 +20,7 @@ import {
   type DocumentQuery,
   getCurrentAccount,
   isOtherDay,
+  type Lookup,
   type Ref,
   SortingOrder,
   type Space,
@@ -119,7 +120,7 @@ export class ChannelDataProvider implements IChannelDataProvider {
   })
 
   constructor (
-    readonly context: DocNotifyContext | undefined,
+    private context: DocNotifyContext | undefined,
     readonly space: Ref<Space>,
     chatId: Ref<Doc>,
     _class: Ref<Class<ActivityMessage>>,
@@ -209,6 +210,13 @@ export class ChannelDataProvider implements IChannelDataProvider {
     )
   }
 
+  async updateNewTimestamp (context?: DocNotifyContext): Promise<void> {
+    this.context = context ?? this.context
+    const firstNewMsgIndex = await this.getFirstNewMsgIndex()
+    const metadata = get(this.metadataStore)
+    this.newTimestampStore.set(firstNewMsgIndex !== undefined ? metadata[firstNewMsgIndex]?.createdOn : undefined)
+  }
+
   private async loadInitialMessages (
     selectedMsg?: Ref<ActivityMessage>,
     loadAll = false,
@@ -285,13 +293,21 @@ export class ChannelDataProvider implements IChannelDataProvider {
       },
       {
         sort: { createdOn: SortingOrder.Descending },
-        lookup: {
-          _id: { attachments: attachment.class.Attachment, inlineButtons: chunter.class.InlineButton }
-        }
+        lookup: this.getLookup()
       }
     )
   }
 
+  getLookup (): Lookup<ActivityMessage> {
+    return {
+      _id: {
+        attachments: attachment.class.Attachment,
+        inlineButtons: chunter.class.InlineButton,
+        reactions: activity.class.Reaction
+      }
+    }
+  }
+
   isNextLoading (mode: LoadMode): boolean {
     return mode === 'forward' ? get(this.isForwardLoading) : get(this.isBackwardLoading)
   }
@@ -331,9 +347,7 @@ export class ChannelDataProvider implements IChannelDataProvider {
       {
         limit: limit ?? this.limit,
         sort: { createdOn: isBackward ? SortingOrder.Descending : SortingOrder.Ascending },
-        lookup: {
-          _id: { attachments: attachment.class.Attachment, inlineButtons: chunter.class.InlineButton }
-        }
+        lookup: this.getLookup()
       }
     )
 
diff --git a/plugins/chunter-resources/src/components/ChannelScrollView.svelte b/plugins/chunter-resources/src/components/ChannelScrollView.svelte
index 5dffbc7151..d02a25591e 100644
--- a/plugins/chunter-resources/src/components/ChannelScrollView.svelte
+++ b/plugins/chunter-resources/src/components/ChannelScrollView.svelte
@@ -26,7 +26,7 @@
     messageInFocus,
     sortActivityMessages
   } from '@hcengineering/activity-resources'
-  import { Doc, getDay, Ref, Timestamp } from '@hcengineering/core'
+  import { Doc, getCurrentAccount, getDay, Ref, Timestamp } from '@hcengineering/core'
   import { DocNotifyContext } from '@hcengineering/notification'
   import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
   import { getResource } from '@hcengineering/platform'
@@ -72,6 +72,7 @@
   const minMsgHeightRem = 2
   const loadMoreThreshold = 40
 
+  const me = getCurrentAccount()
   const client = getClient()
   const inboxClient = InboxNotificationsClientImpl.getClient()
   const contextByDocStore = inboxClient.contextByDoc
@@ -131,8 +132,23 @@
       }
     })
 
+  let isPageHidden = false
+  let lastMsgBeforeFreeze: Ref<ActivityMessage> | undefined = undefined
+
+  function handleVisibilityChange (): void {
+    if (document.hidden) {
+      isPageHidden = true
+      lastMsgBeforeFreeze = shouldScrollToNew ? displayMessages[displayMessages.length - 1]?._id : undefined
+    } else {
+      if (isPageHidden) {
+        isPageHidden = false
+        void provider.updateNewTimestamp(notifyContext)
+      }
+    }
+  }
+
   function isFreeze (): boolean {
-    return freeze
+    return freeze || isPageHidden
   }
 
   $: displayMessages = filterChatMessages(messages, filters, filterResources, doc._class, selectedFilters)
@@ -295,6 +311,38 @@
     }
   }
 
+  function scrollToStartOfNew (): void {
+    if (!scrollElement || !lastMsgBeforeFreeze) {
+      return
+    }
+
+    const lastIndex = displayMessages.findIndex(({ _id }) => _id === lastMsgBeforeFreeze)
+    if (lastIndex === -1) return
+    const firstNewMessage = displayMessages.find(({ createdBy }, index) => index > lastIndex && createdBy !== me._id)
+
+    if (firstNewMessage === undefined) {
+      scrollToBottom()
+      return
+    }
+
+    const messagesElements = scrollContentBox?.getElementsByClassName('activityMessage')
+    const msgElement = messagesElements?.[firstNewMessage._id as any]
+
+    if (!msgElement) {
+      return
+    }
+
+    const messageRect = msgElement.getBoundingClientRect()
+
+    const topOffset = messageRect.top - 150
+
+    if (topOffset < 0) {
+      scroller?.scrollBy(topOffset)
+    } else if (topOffset > 0) {
+      scroller?.scrollBy(topOffset)
+    }
+  }
+
   async function handleScroll ({ autoScrolling }: ScrollParams): Promise<void> {
     saveScrollPosition()
     updateDownButtonVisibility($metadataStore, displayMessages, scrollElement)
@@ -339,7 +387,7 @@
     return messageRect.top >= containerRect.top && messageRect.bottom - messageRect.height / 2 <= containerRect.bottom
   }
 
-  const messagesToReadAccumulator: DisplayActivityMessage[] = []
+  const messagesToReadAccumulator: Set<DisplayActivityMessage> = new Set<DisplayActivityMessage>()
   let messagesToReadAccumulatorTimer: any
 
   function readViewportMessages (): void {
@@ -359,13 +407,14 @@
       }
 
       if (messageInView(msgElement, containerRect)) {
-        messagesToReadAccumulator.push(message)
+        messagesToReadAccumulator.add(message)
       }
     }
 
     clearTimeout(messagesToReadAccumulatorTimer)
     messagesToReadAccumulatorTimer = setTimeout(() => {
       const messagesToRead = [...messagesToReadAccumulator]
+      messagesToReadAccumulator.clear()
       void readChannelMessages(sortActivityMessages(messagesToRead), notifyContext)
     }, 500)
   }
@@ -555,8 +604,12 @@
       return
     }
 
+    const prevCount = messagesCount
+    messagesCount = newCount
+
     if (isFreeze()) {
-      messagesCount = newCount
+      await wait()
+      scrollToStartOfNew()
       return
     }
 
@@ -565,15 +618,13 @@
     } else if (dateToJump !== undefined) {
       await wait()
       scrollToDate(dateToJump)
-    } else if (shouldScrollToNew && messagesCount > 0 && newCount > messagesCount) {
+    } else if (shouldScrollToNew && prevCount > 0 && newCount > prevCount) {
       await wait()
       scrollToNewMessages()
     } else {
       await wait()
       readViewportMessages()
     }
-
-    messagesCount = newCount
   }
 
   $: void handleMessagesUpdated(displayMessages.length)
@@ -610,10 +661,12 @@
 
   afterUpdate(() => {
     if (!scrollElement) return
-    const { scrollHeight } = scrollElement
+    const { offsetHeight, scrollHeight, scrollTop } = scrollElement
 
-    if (!isInitialScrolling && prevScrollHeight < scrollHeight && isScrollAtBottom) {
+    if (!isInitialScrolling && !isFreeze() && prevScrollHeight < scrollHeight && isScrollAtBottom) {
       scrollToBottom()
+    } else if (isFreeze()) {
+      isScrollAtBottom = scrollHeight <= Math.ceil(scrollTop + offsetHeight)
     }
   })
 
@@ -641,10 +694,12 @@
 
   onMount(() => {
     chatReadMessagesStore.update(() => new Set())
+    document.addEventListener('visibilitychange', handleVisibilityChange)
   })
 
   onDestroy(() => {
     unsubscribe()
+    document.removeEventListener('visibilitychange', handleVisibilityChange)
   })
 
   let showScrollDownButton = false
@@ -715,7 +770,7 @@
 
   const canLoadNextForwardStore = provider.canLoadNextForwardStore
 
-  $: if (!freeze) {
+  $: if (!freeze && !isPageHidden && isScrollInitialized) {
     readViewportMessages()
   }
 </script>
diff --git a/plugins/chunter-resources/src/components/chat/specials/SavedMessages.svelte b/plugins/chunter-resources/src/components/chat/specials/SavedMessages.svelte
index 54a3d3d5ee..d1855f0b59 100644
--- a/plugins/chunter-resources/src/components/chat/specials/SavedMessages.svelte
+++ b/plugins/chunter-resources/src/components/chat/specials/SavedMessages.svelte
@@ -37,14 +37,14 @@
   $: savedMessages = $savedMessagesStore
   $: savedAttachments = $savedAttachmentsStore
 
-  async function openAttachment (attach?: Attachment) {
+  async function openAttachment (attach?: Attachment): Promise<void> {
     if (attach === undefined) {
       return
     }
     const messageId: Ref<ActivityMessage> = attach.attachedTo as Ref<ActivityMessage>
     await client.findOne(activity.class.ActivityMessage, { _id: messageId }).then((res) => {
       if (res !== undefined) {
-        openMessageFromSpecial(res)
+        void openMessageFromSpecial(res)
       }
     })
   }
@@ -62,8 +62,8 @@
       }
     }
   }
-  function handleMessageClicked (message?: ActivityMessage) {
-    openMessageFromSpecial(message)
+  function handleMessageClicked (message?: ActivityMessage): void {
+    void openMessageFromSpecial(message)
   }
 </script>
 
diff --git a/plugins/chunter-resources/src/components/threads/ThreadParentPresenter.svelte b/plugins/chunter-resources/src/components/threads/ThreadParentPresenter.svelte
index 0f9403890f..c0436d5e95 100644
--- a/plugins/chunter-resources/src/components/threads/ThreadParentPresenter.svelte
+++ b/plugins/chunter-resources/src/components/threads/ThreadParentPresenter.svelte
@@ -19,4 +19,11 @@
   export let message: ActivityMessage
 </script>
 
-<ActivityMessagePresenter value={message} hideFooter hoverStyles="filledHover" withShowMore={false} skipLabel />
+<ActivityMessagePresenter
+  value={message}
+  hideFooter
+  hoverStyles="filledHover"
+  withShowMore={false}
+  attachmentImageSize="x-large"
+  skipLabel
+/>
diff --git a/plugins/chunter-resources/src/components/threads/Threads.svelte b/plugins/chunter-resources/src/components/threads/Threads.svelte
index 73c954fba3..3e3a0cc68c 100644
--- a/plugins/chunter-resources/src/components/threads/Threads.svelte
+++ b/plugins/chunter-resources/src/components/threads/Threads.svelte
@@ -19,6 +19,8 @@
   import activity, { ActivityMessage } from '@hcengineering/activity'
   import { PersonAccount } from '@hcengineering/contact'
   import { ActivityMessagePresenter } from '@hcengineering/activity-resources'
+  import notification from '@hcengineering/notification'
+  import attachment from '@hcengineering/attachment'
 
   import chunter from '../../plugin'
   import Header from '../Header.svelte'
@@ -32,15 +34,21 @@
   $: threadsQuery.query(
     activity.class.ActivityMessage,
     {
-      replies: { $exists: true }
+      replies: { $exists: true },
+      [`${notification.mixin.Collaborators}.collaborators`]: me._id
     },
     (res) => {
-      threads = res.filter(
-        ({ createdBy, repliedPersons, replies }) =>
-          (replies !== undefined && replies > 0 && createdBy === me._id) || repliedPersons?.includes(me.person)
-      )
+      threads = res.filter(({ replies }) => (replies ?? 0) > 0)
     },
-    { sort: { modifiedOn: SortingOrder.Descending } }
+    {
+      sort: { modifiedOn: SortingOrder.Descending },
+      lookup: {
+        _id: {
+          attachments: attachment.class.Attachment,
+          reactions: activity.class.Reaction
+        }
+      }
+    }
   )
 </script>
 
diff --git a/plugins/chunter-resources/src/utils.ts b/plugins/chunter-resources/src/utils.ts
index 87b75edcc7..950ea5ec1a 100644
--- a/plugins/chunter-resources/src/utils.ts
+++ b/plugins/chunter-resources/src/utils.ts
@@ -430,11 +430,7 @@ export async function readChannelMessages (
   messages: DisplayActivityMessage[],
   context: DocNotifyContext | undefined
 ): Promise<void> {
-  if (messages.length === 0) {
-    return
-  }
-
-  if (context === undefined) {
+  if (messages.length === 0 || context === undefined) {
     return
   }
 
@@ -442,9 +438,7 @@ export async function readChannelMessages (
   const client = getClient().apply(undefined, 'readViewportMessages')
 
   try {
-    const readMessages = get(chatReadMessagesStore)
-    const allIds = getAllIds(messages).filter((id) => !readMessages.has(id))
-
+    const allIds = getAllIds(messages)
     const notifications = get(inboxClient.activityInboxNotifications)
       .filter(({ attachedTo, $lookup, isViewed }) => {
         if (isViewed) return false
diff --git a/plugins/document-resources/src/components/sidebar/Activity.svelte b/plugins/document-resources/src/components/sidebar/Activity.svelte
index 2a55727b35..c6a02152f9 100644
--- a/plugins/document-resources/src/components/sidebar/Activity.svelte
+++ b/plugins/document-resources/src/components/sidebar/Activity.svelte
@@ -16,7 +16,12 @@
 -->
 <script lang="ts">
   import activity, { ActivityMessage } from '@hcengineering/activity'
-  import { ActivityFilter, ActivityMessagePresenter, canGroupMessages } from '@hcengineering/activity-resources'
+  import {
+    ActivityFilter,
+    ActivityMessagePresenter,
+    canGroupMessages,
+    combineActivityMessages
+  } from '@hcengineering/activity-resources'
   import { SortingOrder } from '@hcengineering/core'
   import { Document } from '@hcengineering/document'
   import { createQuery } from '@hcengineering/presentation'
@@ -33,7 +38,9 @@
     activity.class.ActivityMessage,
     { attachedTo: value._id, space: value.space },
     (res) => {
-      messages = res
+      void combineActivityMessages(res).then((res) => {
+        messages = res
+      })
     },
     {
       sort: {
diff --git a/plugins/view-resources/src/components/MarkupDiffPresenter.svelte b/plugins/view-resources/src/components/MarkupDiffPresenter.svelte
index 3a81fdb9fd..f756ec3753 100644
--- a/plugins/view-resources/src/components/MarkupDiffPresenter.svelte
+++ b/plugins/view-resources/src/components/MarkupDiffPresenter.svelte
@@ -23,6 +23,7 @@
   export let value: Markup | undefined
   export let prevValue: Markup | undefined = undefined
   export let attribute: AnyAttribute | undefined = undefined
+  export let withShowMore = true
 
   export let showOnlyDiff: boolean = false
 
@@ -85,8 +86,14 @@
   }
 </script>
 
-<ShowMore>
+{#if withShowMore}
+  <ShowMore>
+    {#key [value, prevValue]}
+      <MarkupDiffViewer objectClass={attribute?.attributeOf} {content} {comparedVersion} />
+    {/key}
+  </ShowMore>
+{:else}
   {#key [value, prevValue]}
     <MarkupDiffViewer objectClass={attribute?.attributeOf} {content} {comparedVersion} />
   {/key}
-</ShowMore>
+{/if}
diff --git a/plugins/workbench-resources/src/components/sidebar/SidebarExpanded.svelte b/plugins/workbench-resources/src/components/sidebar/SidebarExpanded.svelte
index ef3285a94a..7209b04357 100644
--- a/plugins/workbench-resources/src/components/sidebar/SidebarExpanded.svelte
+++ b/plugins/workbench-resources/src/components/sidebar/SidebarExpanded.svelte
@@ -21,7 +21,8 @@
     location as locationStore,
     Location,
     Header,
-    Breadcrumbs
+    Breadcrumbs,
+    getCurrentLocation
   } from '@hcengineering/ui'
   import { onDestroy } from 'svelte'
 
@@ -45,13 +46,33 @@
   $: widgetState = widget !== undefined ? $sidebarStore.widgetsState.get(widget._id) : undefined
 
   $: tabId = widgetState?.tab
-  $: tabs = widgetState?.tabs ?? []
+  $: tabs = getTabs(widget, widgetState)
   $: tab = tabId !== undefined ? tabs.find((it) => it.id === tabId) ?? tabs[0] : tabs[0]
 
   $: if ($sidebarStore.widget === undefined) {
     sidebarStore.update((s) => ({ ...s, variant: SidebarVariant.MINI }))
   }
 
+  function getTabs (widget?: Widget, state?: WidgetState): WidgetTab[] {
+    if (widget === undefined || !state?.tabs) return []
+    const loc = getCurrentLocation()
+
+    const result: WidgetTab[] = []
+    for (const tab of state.tabs) {
+      if (tab.allowedPath !== undefined && !tab.isPinned) {
+        const path = loc.path.join('/')
+        if (!path.startsWith(tab.allowedPath)) {
+          void handleTabClose(tab.id, widget)
+          continue
+        }
+      }
+
+      result.push(tab)
+    }
+
+    return result
+  }
+
   const unsubscribe = locationStore.subscribe((loc: Location) => {
     if (widget === undefined) return
 
diff --git a/server-plugins/activity-resources/src/references.ts b/server-plugins/activity-resources/src/references.ts
index d2e66a7531..f260299f70 100644
--- a/server-plugins/activity-resources/src/references.ts
+++ b/server-plugins/activity-resources/src/references.ts
@@ -248,7 +248,7 @@ export async function getPersonNotificationTxes (
         ...content,
         docNotifyContext: context._id,
         _id: generateId(),
-        _class: notification.class.CommonInboxNotification,
+        _class: notification.class.MentionInboxNotification,
         space: receiverSpace._id,
         modifiedOn: originTx.modifiedOn,
         modifiedBy: sender._id
diff --git a/server-plugins/notification-resources/src/index.ts b/server-plugins/notification-resources/src/index.ts
index 9390692e34..a09e410c19 100644
--- a/server-plugins/notification-resources/src/index.ts
+++ b/server-plugins/notification-resources/src/index.ts
@@ -78,7 +78,7 @@ import serverNotification, {
   SenderInfo
 } from '@hcengineering/server-notification'
 import serverView from '@hcengineering/server-view'
-import { markupToHTML, markupToText, stripTags } from '@hcengineering/text'
+import { markupToText, stripTags } from '@hcengineering/text'
 import { encodeObjectURI } from '@hcengineering/view'
 import { workbenchId } from '@hcengineering/workbench'
 import webpush, { WebPushError } from 'web-push'
@@ -240,8 +240,10 @@ export async function getContentByTemplate (
     notificationData !== undefined &&
     control.hierarchy.isDerived(notificationData._class, notification.class.MentionInboxNotification)
   ) {
-    const text = (notificationData as MentionInboxNotification).messageHtml
-    params.body = text !== undefined ? markupToHTML(text) : params.body
+    const messageContent = (notificationData as MentionInboxNotification).messageHtml
+    const text = messageContent !== undefined ? markupToText(messageContent) : undefined
+    params.body = text ?? params.body
+    params.message = text ?? params.message
   }
 
   if (message !== undefined) {
diff --git a/services/github/pod-github/src/platform.ts b/services/github/pod-github/src/platform.ts
index 626f1237fd..57091ea7d4 100644
--- a/services/github/pod-github/src/platform.ts
+++ b/services/github/pod-github/src/platform.ts
@@ -698,16 +698,16 @@ export class PlatformWorker {
           errors++
           return
         }
+        if (workspaceInfo?.workspace === undefined) {
+          this.ctx.error('No workspace exists for workspaceId', { workspace })
+          errors++
+          return
+        }
+        if (workspaceInfo?.disabled === true) {
+          this.ctx.error('Workspace is disabled workspaceId', { workspace })
+          return
+        }
         try {
-          if (workspaceInfo?.workspace === undefined) {
-            this.ctx.error('No workspace exists for workspaceId', { workspace })
-            errors++
-            return
-          }
-          if (workspaceInfo?.disabled === true) {
-            this.ctx.error('Workspace is disabled workspaceId', { workspace })
-            return
-          }
           const branding = Object.values(this.brandingMap).find((b) => b.key === workspaceInfo?.branding) ?? null
           const workerCtx = this.ctx.newChild('worker', { workspace: workspaceInfo.workspace }, {})