From bdf620f9fee9a5607325d7d6a2f531ca7d16dada Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Wed, 28 Jan 2026 11:01:42 +0100 Subject: [PATCH 01/70] feat: add mark as bot, and reload page after --- .../components/list/member-list-toolbar.vue | 71 +++++++++++++++++++ .../modules/member/pages/member-list-page.vue | 15 +++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/frontend/src/modules/member/components/list/member-list-toolbar.vue b/frontend/src/modules/member/components/list/member-list-toolbar.vue index 8aae013644..1e2ab96c4d 100644 --- a/frontend/src/modules/member/components/list/member-list-toolbar.vue +++ b/frontend/src/modules/member/components/list/member-list-toolbar.vue @@ -34,6 +34,16 @@ {{ markAsTeamMemberOptions.copy }} + + + {{ markAsBotOptions.copy }} + { }; }); +const markAsBotOptions = computed(() => { + const membersCopy = pluralize( + 'person', + selectedMembers.value.length, + false, + ); + + // Check if any of the selected members is already marked as bot + const hasBot = selectedMembers.value.some((member) => member.attributes?.isBot?.default); + + if (hasBot) { + return { + icon: 'robot', + copy: 'Unmark as bot', + value: false, + }; + } + + return { + icon: 'robot', + copy: 'Mark as bot', + value: true, + }; +}); + const handleMergeMembers = async () => { const [firstMember, secondMember] = selectedMembers.value; @@ -247,6 +282,31 @@ const doMarkAsTeamMember = async (value) => { }); }; +const doMarkAsBot = async (value) => { + ToastStore.info('People are being updated'); + + return Promise.all(selectedMembers.value.map((member) => MemberService.update(member.id, { + attributes: { + ...member.attributes, + isBot: { + default: value, + custom: value, + }, + }, + }, member.segmentIds))) + .then(() => { + ToastStore.closeAll(); + ToastStore.success(`${ + pluralize('Person', selectedMembers.value.length, true)} updated successfully`); + + fetchMembers({ reload: true }); + }) + .catch(() => { + ToastStore.closeAll(); + ToastStore.error('Error updating people'); + }); +}; + const handleCommand = async (command) => { if (command.action === 'markAsTeamMember') { trackEvent({ @@ -259,6 +319,17 @@ const handleCommand = async (command) => { }); await doMarkAsTeamMember(command.value); + } else if (command.action === 'markAsBot') { + trackEvent({ + key: FeatureEventKey.MARK_AS_BOT, + type: EventType.FEATURE, + properties: { + path: route.path, + bulk: true, + }, + }); + + await doMarkAsBot(command.value); } else if (command.action === 'export') { await handleDoExport(); } else if (command.action === 'mergeMembers') { diff --git a/frontend/src/modules/member/pages/member-list-page.vue b/frontend/src/modules/member/pages/member-list-page.vue index 3e51b81d51..6ea7881921 100644 --- a/frontend/src/modules/member/pages/member-list-page.vue +++ b/frontend/src/modules/member/pages/member-list-page.vue @@ -206,12 +206,23 @@ watch(membersData, (newData) => { // Update the Pinia store with the new data memberStore.members = newData.rows || []; memberStore.totalMembers = newData.count || 0; + + // Build the correct transformed filter for savedFilterBody + const transformedFilter = filters.value + ? buildApiFilter( + filters.value, + { ...memberFilters, ...customAttributesFilter.value }, + memberSearchFilter, + memberSavedViews, + ) + : { search: '', filter: {}, orderBy: 'activityCount_DESC' }; + memberStore.savedFilterBody = { search: queryParams.value.search, - filter: filters.value, + filter: transformedFilter.filter, offset: queryParams.value.offset, limit: queryParams.value.limit, - orderBy: queryParams.value.orderBy, + orderBy: transformedFilter.orderBy, }; } }, { immediate: true }); From 483ffef7a7578adf3401623ca711a76d49cb2b17 Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Wed, 28 Jan 2026 11:21:06 +0100 Subject: [PATCH 02/70] fix: caching issue --- .../components/list/member-list-toolbar.vue | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/frontend/src/modules/member/components/list/member-list-toolbar.vue b/frontend/src/modules/member/components/list/member-list-toolbar.vue index 1e2ab96c4d..d36d6e6635 100644 --- a/frontend/src/modules/member/components/list/member-list-toolbar.vue +++ b/frontend/src/modules/member/components/list/member-list-toolbar.vue @@ -95,10 +95,13 @@ import { EventType, FeatureEventKey } from '@/shared/modules/monitoring/types/ev import LfIcon from '@/ui-kit/icon/Icon.vue'; import LfButton from '@/ui-kit/button/Button.vue'; import LfTableBulkActions from '@/ui-kit/table/table-bulk-actions.vue'; +import { useQueryClient } from '@tanstack/vue-query'; +import { TanstackKey } from '@/shared/types/tanstack'; const { trackEvent } = useProductTracking(); const route = useRoute(); +const queryClient = useQueryClient(); const authStore = useAuthStore(); const { getUser } = authStore; @@ -268,12 +271,17 @@ const doMarkAsTeamMember = async (value) => { default: value, }, }, - }, member.segmentIds))) + }))) .then(() => { ToastStore.closeAll(); ToastStore.success(`${ pluralize('Person', selectedMembers.value.length, true)} updated successfully`); + // Invalidate React Query cache + queryClient.invalidateQueries({ + queryKey: [TanstackKey.MEMBERS_LIST], + }); + fetchMembers({ reload: true }); }) .catch(() => { @@ -293,12 +301,17 @@ const doMarkAsBot = async (value) => { custom: value, }, }, - }, member.segmentIds))) + }))) .then(() => { ToastStore.closeAll(); ToastStore.success(`${ pluralize('Person', selectedMembers.value.length, true)} updated successfully`); + // Invalidate React Query cache + queryClient.invalidateQueries({ + queryKey: [TanstackKey.MEMBERS_LIST], + }); + fetchMembers({ reload: true }); }) .catch(() => { From ea50c95f108ae8146ee5cf5ee3e2583aad267828 Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Wed, 28 Jan 2026 11:38:41 +0100 Subject: [PATCH 03/70] fix: refetch --- .../member/components/list/member-list-toolbar.vue | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/frontend/src/modules/member/components/list/member-list-toolbar.vue b/frontend/src/modules/member/components/list/member-list-toolbar.vue index d36d6e6635..269db40cbb 100644 --- a/frontend/src/modules/member/components/list/member-list-toolbar.vue +++ b/frontend/src/modules/member/components/list/member-list-toolbar.vue @@ -266,7 +266,7 @@ const doMarkAsTeamMember = async (value) => { return Promise.all(selectedMembers.value.map((member) => MemberService.update(member.id, { attributes: { - ...member.attributes, + ...(member.attributes || {}), isTeamMember: { default: value, }, @@ -277,12 +277,11 @@ const doMarkAsTeamMember = async (value) => { ToastStore.success(`${ pluralize('Person', selectedMembers.value.length, true)} updated successfully`); - // Invalidate React Query cache + // Force React Query to refetch by invalidating with refetch queryClient.invalidateQueries({ queryKey: [TanstackKey.MEMBERS_LIST], + refetchType: 'active', }); - - fetchMembers({ reload: true }); }) .catch(() => { ToastStore.closeAll(); @@ -295,7 +294,7 @@ const doMarkAsBot = async (value) => { return Promise.all(selectedMembers.value.map((member) => MemberService.update(member.id, { attributes: { - ...member.attributes, + ...(member.attributes || {}), isBot: { default: value, custom: value, @@ -307,12 +306,11 @@ const doMarkAsBot = async (value) => { ToastStore.success(`${ pluralize('Person', selectedMembers.value.length, true)} updated successfully`); - // Invalidate React Query cache + // Force React Query to refetch by invalidating with refetch queryClient.invalidateQueries({ queryKey: [TanstackKey.MEMBERS_LIST], + refetchType: 'active', }); - - fetchMembers({ reload: true }); }) .catch(() => { ToastStore.closeAll(); From 2a0fe55a1ec5c5cfa059fb287a9995ee00bc299c Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Wed, 28 Jan 2026 11:48:20 +0100 Subject: [PATCH 04/70] fix: refetch --- .../components/member-dropdown-content.vue | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/frontend/src/modules/member/components/member-dropdown-content.vue b/frontend/src/modules/member/components/member-dropdown-content.vue index 6a8c194767..87d117dbe4 100644 --- a/frontend/src/modules/member/components/member-dropdown-content.vue +++ b/frontend/src/modules/member/components/member-dropdown-content.vue @@ -166,6 +166,8 @@ import { LfPermission } from '@/shared/modules/permissions/types/Permissions'; import useProductTracking from '@/shared/modules/monitoring/useProductTracking'; import { EventType, FeatureEventKey } from '@/shared/modules/monitoring/types/event'; import LfIcon from '@/ui-kit/icon/Icon.vue'; +import { useQueryClient } from '@tanstack/vue-query'; +import { TanstackKey } from '@/shared/types/tanstack'; import { Member } from '../types/Member'; enum Actions { @@ -189,6 +191,7 @@ const props = defineProps<{ }>(); const route = useRoute(); +const queryClient = useQueryClient(); const { doFind } = mapActions('member'); @@ -322,7 +325,7 @@ const handleCommand = async (command: { errorMessage: 'Something went wrong', actionFn: MemberService.update(command.member.id, { attributes: { - ...command.member.attributes, + ...(command.member.attributes || {}), isTeamMember: { default: command.value, custom: command.value, @@ -330,6 +333,12 @@ const handleCommand = async (command: { }, }), }).then(() => { + // Invalidate React Query cache for member list pages + queryClient.invalidateQueries({ + queryKey: [TanstackKey.MEMBERS_LIST], + refetchType: 'active', + }); + if (route.name === 'member') { memberStore.fetchMembers({ reload: true }); } else { @@ -362,7 +371,7 @@ const handleCommand = async (command: { errorMessage: 'Something went wrong', actionFn: MemberService.update(command.member.id, { attributes: { - ...command.member.attributes, + ...(command.member.attributes || {}), isBot: { default: command.action === Actions.MARK_CONTACT_AS_BOT, custom: command.action === Actions.MARK_CONTACT_AS_BOT, @@ -370,6 +379,12 @@ const handleCommand = async (command: { }, }), }).then(() => { + // Invalidate React Query cache for member list pages + queryClient.invalidateQueries({ + queryKey: [TanstackKey.MEMBERS_LIST], + refetchType: 'active', + }); + if (route.name === 'member') { memberStore.fetchMembers({ reload: true }); } else { From 2fcc93224088050f3e4233fc82fae20fd58bc6a8 Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Wed, 28 Jan 2026 11:52:32 +0100 Subject: [PATCH 05/70] fix: adding logs --- .../components/list/member-list-toolbar.vue | 38 ++++++++++++---- .../components/member-dropdown-content.vue | 43 +++++++++++++------ scripts/cli | 4 +- 3 files changed, 61 insertions(+), 24 deletions(-) diff --git a/frontend/src/modules/member/components/list/member-list-toolbar.vue b/frontend/src/modules/member/components/list/member-list-toolbar.vue index 269db40cbb..10bc5f2a1d 100644 --- a/frontend/src/modules/member/components/list/member-list-toolbar.vue +++ b/frontend/src/modules/member/components/list/member-list-toolbar.vue @@ -262,16 +262,27 @@ const handleEditAttribute = async () => { }; const doMarkAsTeamMember = async (value) => { + console.log('[TOOLBAR] Mark as team member - Selected members count:', selectedMembers.value.length); + console.log('[TOOLBAR] Mark as team member - Value:', value); + ToastStore.info('People are being updated'); - return Promise.all(selectedMembers.value.map((member) => MemberService.update(member.id, { - attributes: { + return Promise.all(selectedMembers.value.map((member) => { + console.log('[TOOLBAR] Mark as team member - Member ID:', member.id, 'Current attributes:', member.attributes); + + const updatedAttributes = { ...(member.attributes || {}), isTeamMember: { default: value, }, - }, - }))) + }; + + console.log('[TOOLBAR] Mark as team member - Updated attributes for', member.id, ':', updatedAttributes); + + return MemberService.update(member.id, { + attributes: updatedAttributes, + }); + })) .then(() => { ToastStore.closeAll(); ToastStore.success(`${ @@ -290,17 +301,28 @@ const doMarkAsTeamMember = async (value) => { }; const doMarkAsBot = async (value) => { + console.log('[TOOLBAR] Mark as bot - Selected members count:', selectedMembers.value.length); + console.log('[TOOLBAR] Mark as bot - Value:', value); + ToastStore.info('People are being updated'); - return Promise.all(selectedMembers.value.map((member) => MemberService.update(member.id, { - attributes: { + return Promise.all(selectedMembers.value.map((member) => { + console.log('[TOOLBAR] Mark as bot - Member ID:', member.id, 'Current attributes:', member.attributes); + + const updatedAttributes = { ...(member.attributes || {}), isBot: { default: value, custom: value, }, - }, - }))) + }; + + console.log('[TOOLBAR] Mark as bot - Updated attributes for', member.id, ':', updatedAttributes); + + return MemberService.update(member.id, { + attributes: updatedAttributes, + }); + })) .then(() => { ToastStore.closeAll(); ToastStore.success(`${ diff --git a/frontend/src/modules/member/components/member-dropdown-content.vue b/frontend/src/modules/member/components/member-dropdown-content.vue index 87d117dbe4..488c1df5e3 100644 --- a/frontend/src/modules/member/components/member-dropdown-content.vue +++ b/frontend/src/modules/member/components/member-dropdown-content.vue @@ -311,6 +311,19 @@ const handleCommand = async (command: { // Mark as team contact if (command.action === Actions.MARK_CONTACT_AS_TEAM_CONTACT) { + console.log('[DROPDOWN] Mark as team member - Current attributes:', command.member.attributes); + console.log('[DROPDOWN] Mark as team member - Value:', command.value); + + const updatedAttributes = { + ...(command.member.attributes || {}), + isTeamMember: { + default: command.value, + custom: command.value, + }, + }; + + console.log('[DROPDOWN] Mark as team member - Updated attributes:', updatedAttributes); + trackEvent({ key: FeatureEventKey.MARK_AS_TEAM_MEMBER, type: EventType.FEATURE, @@ -324,13 +337,7 @@ const handleCommand = async (command: { successMessage: 'Profile updated successfully', errorMessage: 'Something went wrong', actionFn: MemberService.update(command.member.id, { - attributes: { - ...(command.member.attributes || {}), - isTeamMember: { - default: command.value, - custom: command.value, - }, - }, + attributes: updatedAttributes, }), }).then(() => { // Invalidate React Query cache for member list pages @@ -357,6 +364,20 @@ const handleCommand = async (command: { command.action === Actions.MARK_CONTACT_AS_BOT || command.action === Actions.UNMARK_CONTACT_AS_BOT ) { + const isMarkingAsBot = command.action === Actions.MARK_CONTACT_AS_BOT; + console.log('[DROPDOWN] Mark as bot - Current attributes:', command.member.attributes); + console.log('[DROPDOWN] Mark as bot - Action:', command.action, 'IsMarkingAsBot:', isMarkingAsBot); + + const updatedAttributes = { + ...(command.member.attributes || {}), + isBot: { + default: isMarkingAsBot, + custom: isMarkingAsBot, + }, + }; + + console.log('[DROPDOWN] Mark as bot - Updated attributes:', updatedAttributes); + trackEvent({ key: FeatureEventKey.MARK_AS_BOT, type: EventType.FEATURE, @@ -370,13 +391,7 @@ const handleCommand = async (command: { successMessage: 'Profile updated successfully', errorMessage: 'Something went wrong', actionFn: MemberService.update(command.member.id, { - attributes: { - ...(command.member.attributes || {}), - isBot: { - default: command.action === Actions.MARK_CONTACT_AS_BOT, - custom: command.action === Actions.MARK_CONTACT_AS_BOT, - }, - }, + attributes: updatedAttributes, }), }).then(() => { // Invalidate React Query cache for member list pages diff --git a/scripts/cli b/scripts/cli index d093605872..76bf60a23b 100755 --- a/scripts/cli +++ b/scripts/cli @@ -700,7 +700,7 @@ function migrate_productdb_local() { function migrate_local() { migrate_postgres_local migrate_productdb_local - migrate_tinybird_local + # migrate_tinybird_local } function up_test_scaffold() { @@ -927,7 +927,7 @@ while test $# -gt 0; do exit ;; clean-start-dev) - # IGNORED_SERVICES=("python-worker" "job-generator" "discord-ws" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker") + IGNORED_SERVICES=("python-worker" "job-generator" "discord-ws" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker") CLEAN_START=1 DEV=1 start From bb6e28a835327abe58211c2e76fee3a9d73b0ede Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Wed, 28 Jan 2026 12:12:43 +0100 Subject: [PATCH 06/70] fix: optiomize cache --- .../components/list/member-list-toolbar.vue | 14 +++++++++--- .../components/member-dropdown-content.vue | 22 ++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/frontend/src/modules/member/components/list/member-list-toolbar.vue b/frontend/src/modules/member/components/list/member-list-toolbar.vue index 10bc5f2a1d..8232e7ed2a 100644 --- a/frontend/src/modules/member/components/list/member-list-toolbar.vue +++ b/frontend/src/modules/member/components/list/member-list-toolbar.vue @@ -75,7 +75,7 @@ diff --git a/services/libs/data-access-layer/src/members/base.ts b/services/libs/data-access-layer/src/members/base.ts index 0a2d5e78a8..2bbd4371d9 100644 --- a/services/libs/data-access-layer/src/members/base.ts +++ b/services/libs/data-access-layer/src/members/base.ts @@ -42,6 +42,7 @@ interface IQueryMembersAdvancedParams { countOnly?: boolean fields?: string[] includeAllAttributes?: boolean + cachebust?: string // Add cache busting parameter include?: { identities?: boolean segments?: boolean @@ -150,6 +151,7 @@ export async function queryMembersAdvanced( countOnly = false, fields = [...QUERY_FILTER_COLUMN_MAP.keys()], includeAllAttributes = false, + cachebust = undefined, // Add cache busting parameter include = { identities: true, segments: false, @@ -168,6 +170,11 @@ export async function queryMembersAdvanced( attributeSettings = [] as IDbMemberAttributeSetting[], }, ): Promise> { + // Log cache busting for debugging + if (cachebust) { + log.info(`[DEBUG] queryMembersAdvanced with cache bust [${cachebust}]`) + } + // Log input parameters for debugging log.info('[DEBUG] queryMembersAdvanced input:', { filter, @@ -198,11 +205,20 @@ export async function queryMembersAdvanced( segmentId, }) - // Try to get from cache first - const cachedResult = countOnly ? null : await cache.get(cacheKey) - const cachedCount = countOnly ? await cache.getCount(cacheKey) : null + // Try to get from cache first - but bypass cache if cachebust is present + const cachedResult = (countOnly || cachebust) ? null : await cache.get(cacheKey) + const cachedCount = (countOnly || cachebust) ? null : await cache.getCount(cacheKey) + + // Log cache behavior for debugging + if (cachebust) { + log.info(`[DEBUG] Cache bypassed due to cachebust parameter [${cachebust}]`) + } else if (cachedResult) { + log.info('[DEBUG] Cache hit - returning cached result') + } else { + log.info('[DEBUG] Cache miss - executing fresh query') + } - if (cachedResult) { + if (cachedResult && !cachebust) { refreshCacheInBackground(bgQx, redis, cacheKey, { filter, search, From cc380431816eb3e567aa4d067e85eddfd436b040 Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Thu, 29 Jan 2026 18:51:22 +0100 Subject: [PATCH 59/70] fix: revert approach with backend cache bypass --- .../components/list/member-list-toolbar.vue | 53 +++++++++--------- .../components/member-dropdown-content.vue | 54 ++++++------------- .../data-access-layer/src/members/base.ts | 4 +- 3 files changed, 46 insertions(+), 65 deletions(-) diff --git a/frontend/src/modules/member/components/list/member-list-toolbar.vue b/frontend/src/modules/member/components/list/member-list-toolbar.vue index d467487cc8..e09220ebb3 100644 --- a/frontend/src/modules/member/components/list/member-list-toolbar.vue +++ b/frontend/src/modules/member/components/list/member-list-toolbar.vue @@ -74,7 +74,7 @@ From 9ef3a93fffe1fe705e3bad36307b7d7da4b6b410 Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Fri, 30 Jan 2026 09:41:54 +0100 Subject: [PATCH 67/70] fix: remove cachebust flag --- backend/src/api/member/memberFind.ts | 7 ------ backend/src/api/member/memberQuery.ts | 9 +------ .../database/repositories/memberRepository.ts | 7 ------ backend/src/services/memberService.ts | 17 ++----------- .../components/list/member-list-toolbar.vue | 6 +---- .../components/member-dropdown-content.vue | 9 +------ frontend/src/modules/member/member-service.js | 4 ++-- .../data-access-layer/src/members/base.ts | 24 ++++--------------- 8 files changed, 11 insertions(+), 72 deletions(-) diff --git a/backend/src/api/member/memberFind.ts b/backend/src/api/member/memberFind.ts index 3ceb41326d..d4e38ef6d3 100644 --- a/backend/src/api/member/memberFind.ts +++ b/backend/src/api/member/memberFind.ts @@ -22,7 +22,6 @@ export default async (req, res) => { const segmentId = req.query.segments?.length > 0 ? req.query.segments[0] : null const includeAllAttributes = req.query.includeAllAttributes === 'true' || req.query.includeAllAttributes === true - const cachebust = req.query._cachebust || null if (!segmentId) { await req.responseHandler.error(req, res, { @@ -32,17 +31,11 @@ export default async (req, res) => { return } - // Log cache busting parameter for debugging - if (cachebust) { - console.log(`đŸšĢ Cache bust request for member ${req.params.id} [${cachebust}]`) - } - const payload = await new MemberService(req).findById( req.params.id, segmentId, req.query.include, includeAllAttributes, - { cachebust }, // Pass cache busting parameter to service ) await req.responseHandler.success(req, res, payload) diff --git a/backend/src/api/member/memberQuery.ts b/backend/src/api/member/memberQuery.ts index 32367748b5..f7bc8bf51b 100644 --- a/backend/src/api/member/memberQuery.ts +++ b/backend/src/api/member/memberQuery.ts @@ -20,15 +20,8 @@ import PermissionChecker from '../../services/user/permissionChecker' export default async (req, res) => { new PermissionChecker(req).validateHas(Permissions.values.memberRead) - const cachebust = req.query._cachebust || null - - // Log cache busting parameter for debugging - if (cachebust) { - console.log(`đŸšĢ Cache bust request for member query [${cachebust}]`) - } - const memberService = new MemberService(req) - const payload = await memberService.query(req.body, { cachebust }) + const payload = await memberService.query(req.body) if (req.body.filter && Object.keys(req.body.filter).length > 0) { track('Member Advanced Filter', { ...req.body }, { ...req }) diff --git a/backend/src/database/repositories/memberRepository.ts b/backend/src/database/repositories/memberRepository.ts index be726cee28..12a59fb84b 100644 --- a/backend/src/database/repositories/memberRepository.ts +++ b/backend/src/database/repositories/memberRepository.ts @@ -1191,25 +1191,18 @@ class MemberRepository { } = {}, include: Record = {}, includeAllAttributes = false, - cacheOptions: { cachebust?: string } = {}, ) { let memberResponse = null const qx = optionsQx(options) const bgQx = optionsQx({ ...options, transaction: null }) - // Log cache busting for debugging - if (cacheOptions.cachebust) { - console.log(`đŸšĢ MemberRepository.findById with cache bust: ${id} [${cacheOptions.cachebust}]`) - } - memberResponse = await queryMembersAdvanced(qx, bgQx, options.redis, { filter: { id: { eq: id } }, limit: 1, offset: 0, segmentId, includeAllAttributes, - cachebust: cacheOptions.cachebust, // Pass cache busting to query function include: { memberOrganizations: false, lfxMemberships: true, diff --git a/backend/src/services/memberService.ts b/backend/src/services/memberService.ts index 71f0a5d241..118f455478 100644 --- a/backend/src/services/memberService.ts +++ b/backend/src/services/memberService.ts @@ -1366,13 +1366,7 @@ export default class MemberService extends LoggerBase { segmentId?: string, include: Record = {}, includeAllAttributes = false, - options: { cachebust?: string } = {}, ) { - // Log cache busting for debugging - if (options.cachebust) { - console.log(`đŸšĢ MemberService.findById with cache bust: ${id} [${options.cachebust}]`) - } - return MemberRepository.findById( id, this.options, @@ -1381,7 +1375,6 @@ export default class MemberService extends LoggerBase { }, include, includeAllAttributes, - options, ) } @@ -1423,12 +1416,7 @@ export default class MemberService extends LoggerBase { ) } - async query(data, options: { cachebust?: string } = {}, exportMode = false) { - // Log cache busting for debugging - if (options.cachebust) { - console.log(`đŸšĢ MemberService.query with cache bust [${options.cachebust}]`) - } - + async query(data, exportMode = false) { const memberAttributeSettings = ( await MemberAttributeSettingsRepository.findAndCountAll({}, this.options) ).rows.filter((setting) => setting.type !== MemberAttributeType.SPECIAL) @@ -1446,7 +1434,6 @@ export default class MemberService extends LoggerBase { ...data, segmentId, attributesSettings: memberAttributeSettings, - cachebust: options.cachebust, // Pass cache busting to query function include: { memberOrganizations: true, lfxMemberships: true, @@ -1502,7 +1489,7 @@ export default class MemberService extends LoggerBase { await cache.invalidateByPattern(`members_advanced:${memberId}:*`) } this.log.debug(`Invalidated member query cache for ${memberIds.length} specific members`) - + // Only invalidate all caches if explicitly requested // This is useful for operations like update/delete that affect list views if (invalidateAll) { diff --git a/frontend/src/modules/member/components/list/member-list-toolbar.vue b/frontend/src/modules/member/components/list/member-list-toolbar.vue index 3dadc331e8..6b35642a2a 100644 --- a/frontend/src/modules/member/components/list/member-list-toolbar.vue +++ b/frontend/src/modules/member/components/list/member-list-toolbar.vue @@ -121,19 +121,15 @@ const refreshMemberData = async () => { }); }; -// Helper function to fetch member with all attributes before bulk update - with cache busting +// Helper function to fetch member with all attributes before bulk update const fetchMemberWithAllAttributes = async (memberId) => { const lsSegmentsStore = useLfSegmentsStore(); const { selectedProjectGroup } = storeToRefs(lsSegmentsStore); - // Add cache busting timestamp to force fresh backend data - const timestamp = Date.now(); - const response = await MemberService.find( memberId, selectedProjectGroup.value?.id, true, - { _cachebust: timestamp }, ); return response; diff --git a/frontend/src/modules/member/components/member-dropdown-content.vue b/frontend/src/modules/member/components/member-dropdown-content.vue index d0381fb8a6..20b5d046a8 100644 --- a/frontend/src/modules/member/components/member-dropdown-content.vue +++ b/frontend/src/modules/member/components/member-dropdown-content.vue @@ -212,16 +212,12 @@ const refreshMemberData = async () => { }); }; -// Helper function to fetch member with all attributes before update - with cache busting +// Helper function to fetch member with all attributes before update const fetchMemberWithAllAttributes = async (memberId: string) => { - const timestamp = Date.now(); - - // Add cache busting parameter to force fresh backend data const response = await MemberService.find( memberId, selectedProjectGroup.value?.id, true, - { _cachebust: timestamp }, ); return response; @@ -298,8 +294,6 @@ const handleCommand = async (command: { } // Sync with hubspot - // TODO: Re-enable when HubspotApiService is available - /* if ( command.action === Actions.SYNC_HUBSPOT || command.action === Actions.STOP_SYNC_HUBSPOT @@ -330,7 +324,6 @@ const handleCommand = async (command: { return; } - */ // Mark as team contact if (command.action === Actions.MARK_CONTACT_AS_TEAM_CONTACT) { diff --git a/frontend/src/modules/member/member-service.js b/frontend/src/modules/member/member-service.js index f93e6e060b..8739f27550 100644 --- a/frontend/src/modules/member/member-service.js +++ b/frontend/src/modules/member/member-service.js @@ -96,7 +96,7 @@ export class MemberService { memberOrganizations: true, attributes: true, }, - ...additionalParams, // Add support for additional parameters like _cachebust + ...additionalParams, }, }); @@ -159,7 +159,7 @@ export class MemberService { headers: { 'x-crowd-api-version': '1', }, - params: additionalParams, // Add support for additional parameters like _cachebust + params: additionalParams, }, ); diff --git a/services/libs/data-access-layer/src/members/base.ts b/services/libs/data-access-layer/src/members/base.ts index c6333656fd..6dd2a4c1f9 100644 --- a/services/libs/data-access-layer/src/members/base.ts +++ b/services/libs/data-access-layer/src/members/base.ts @@ -42,7 +42,6 @@ interface IQueryMembersAdvancedParams { countOnly?: boolean fields?: string[] includeAllAttributes?: boolean - cachebust?: string // Add cache busting parameter include?: { identities?: boolean segments?: boolean @@ -151,7 +150,6 @@ export async function queryMembersAdvanced( countOnly = false, fields = [...QUERY_FILTER_COLUMN_MAP.keys()], includeAllAttributes = false, - cachebust = undefined, // Add cache busting parameter include = { identities: true, segments: false, @@ -170,11 +168,6 @@ export async function queryMembersAdvanced( attributeSettings = [] as IDbMemberAttributeSetting[], }, ): Promise> { - // Log cache busting for debugging - if (cachebust) { - log.info(`[DEBUG] queryMembersAdvanced with cache bust [${cachebust}]`) - } - // Log input parameters for debugging log.info('[DEBUG] queryMembersAdvanced input:', { filter, @@ -205,20 +198,11 @@ export async function queryMembersAdvanced( segmentId, }) - // Try to get from cache first - but bypass cache if cachebust is present - const cachedResult = countOnly || cachebust ? null : await cache.get(cacheKey) - const cachedCount = countOnly || cachebust ? null : await cache.getCount(cacheKey) - - // Log cache behavior for debugging - if (cachebust) { - log.info(`[DEBUG] Cache bypassed due to cachebust parameter [${cachebust}]`) - } else if (cachedResult) { - log.info('[DEBUG] Cache hit - returning cached result') - } else { - log.info('[DEBUG] Cache miss - executing fresh query') - } + // Try to get from cache first + const cachedResult = countOnly ? null : await cache.get(cacheKey) + const cachedCount = countOnly ? null : await cache.getCount(cacheKey) - if (cachedResult && !cachebust) { + if (cachedResult) { refreshCacheInBackground(bgQx, redis, cacheKey, { filter, search, From c8ecaa49dd54bf383b55c9fa4c0992bb917a4d13 Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Fri, 30 Jan 2026 09:55:22 +0100 Subject: [PATCH 68/70] fix: remove logs and useles params --- frontend/src/modules/member/member-service.js | 6 ++---- scripts/cli | 2 +- services/libs/data-access-layer/src/members/base.ts | 13 ------------- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/frontend/src/modules/member/member-service.js b/frontend/src/modules/member/member-service.js index 8739f27550..a025b4d708 100644 --- a/frontend/src/modules/member/member-service.js +++ b/frontend/src/modules/member/member-service.js @@ -86,7 +86,7 @@ export class MemberService { return response.data; } - static async find(id, segmentId, includeAllAttributes = false, additionalParams = {}) { + static async find(id, segmentId, includeAllAttributes = false) { const response = await authAxios.get(`/member/${id}`, { params: { segments: [segmentId ?? getSelectedProjectGroup().id], @@ -96,7 +96,6 @@ export class MemberService { memberOrganizations: true, attributes: true, }, - ...additionalParams, }, }); @@ -148,7 +147,7 @@ export class MemberService { })); } - static async listMembers(body, countOnly = false, additionalParams = {}) { + static async listMembers(body, countOnly = false) { const response = await authAxios.post( '/member/query', { @@ -159,7 +158,6 @@ export class MemberService { headers: { 'x-crowd-api-version': '1', }, - params: additionalParams, }, ); diff --git a/scripts/cli b/scripts/cli index 23ca6dcd84..d093605872 100755 --- a/scripts/cli +++ b/scripts/cli @@ -927,7 +927,7 @@ while test $# -gt 0; do exit ;; clean-start-dev) - IGNORED_SERVICES=("python-worker" "job-generator" "discord-ws" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker") + # IGNORED_SERVICES=("python-worker" "job-generator" "discord-ws" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker") CLEAN_START=1 DEV=1 start diff --git a/services/libs/data-access-layer/src/members/base.ts b/services/libs/data-access-layer/src/members/base.ts index 6dd2a4c1f9..4f493389a0 100644 --- a/services/libs/data-access-layer/src/members/base.ts +++ b/services/libs/data-access-layer/src/members/base.ts @@ -168,19 +168,6 @@ export async function queryMembersAdvanced( attributeSettings = [] as IDbMemberAttributeSetting[], }, ): Promise> { - // Log input parameters for debugging - log.info('[DEBUG] queryMembersAdvanced input:', { - filter, - search, - limit, - offset, - orderBy, - segmentId, - countOnly, - includeAllAttributes, - fields: fields.length, - }) - // Initialize cache const cache = new MemberQueryCache(redis) From c44877a12cebf48f6c1962b16deb162b103800ee Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Fri, 30 Jan 2026 10:56:28 +0100 Subject: [PATCH 69/70] feat: add currentAttribute in isBot --- .../src/modules/member/components/member-dropdown-content.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/modules/member/components/member-dropdown-content.vue b/frontend/src/modules/member/components/member-dropdown-content.vue index 20b5d046a8..27e8e340a3 100644 --- a/frontend/src/modules/member/components/member-dropdown-content.vue +++ b/frontend/src/modules/member/components/member-dropdown-content.vue @@ -387,6 +387,7 @@ const handleCommand = async (command: { attributes: { ...currentAttributes, isBot: { + ...currentAttributes.isBot, default: isBot, custom: isBot, }, From 6aef90406401aef4c05367058bf7893924edcc1f Mon Sep 17 00:00:00 2001 From: Umberto Sgueglia Date: Fri, 30 Jan 2026 11:24:01 +0100 Subject: [PATCH 70/70] feat: add currentAttribute in isBot --- .../src/modules/member/components/list/member-list-toolbar.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/modules/member/components/list/member-list-toolbar.vue b/frontend/src/modules/member/components/list/member-list-toolbar.vue index 6b35642a2a..e2b7744017 100644 --- a/frontend/src/modules/member/components/list/member-list-toolbar.vue +++ b/frontend/src/modules/member/components/list/member-list-toolbar.vue @@ -339,6 +339,7 @@ const doMarkAsBot = async (value) => { const updatedAttributes = { ...currentAttributes, isBot: { + ...currentAttributes.isBot, default: value, custom: value, },