From 95a56a7d48fdaf9b46a129fb82fabef57ea61b15 Mon Sep 17 00:00:00 2001 From: Yeganathan S <63534555+skwowet@users.noreply.github.com> Date: Wed, 8 Jul 2026 13:53:44 +0530 Subject: [PATCH 1/8] fix: avoid grouping when resolving work experience by id Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com> --- .../work-experiences/updateMemberWorkExperience.ts | 8 +++++--- .../work-experiences/verifyMemberWorkExperience.ts | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/backend/src/api/public/v1/members/work-experiences/updateMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/updateMemberWorkExperience.ts index 62ce2277f0..ed23e35734 100644 --- a/backend/src/api/public/v1/members/work-experiences/updateMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/updateMemberWorkExperience.ts @@ -122,9 +122,11 @@ export async function updateMemberWorkExperience(req: Request, res: Response): P const orgsMap = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { withDomains: true }) - const updatedMo = groupMemberOrganizations(orgsMap.get(memberId) ?? []).find( - (mo) => mo.id === workExperienceId, - ) + const memberOrgsWithData = orgsMap.get(memberId) ?? [] + + const updatedMo = + groupMemberOrganizations(memberOrgsWithData).find((mo) => mo.id === workExperienceId) ?? + memberOrgsWithData.find((mo) => mo.id === workExperienceId) if (!updatedMo) { throw new NotFoundError('Work experience not found') diff --git a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts index 650e3ad92c..0dc9c7cde6 100644 --- a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts @@ -56,9 +56,9 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P withDomains: true, }) - const workExperienceWithOrgData = groupMemberOrganizations( - orgsMapBeforeChange.get(memberId) ?? [], - ).find((mo) => mo.id === workExperienceId) + const memberOrgsWithData = orgsMapBeforeChange.get(memberId) ?? [] + + const workExperienceWithOrgData = memberOrgsWithData.find((mo) => mo.id === workExperienceId) if (!workExperienceWithOrgData) { throw new NotFoundError('Work experience not found') @@ -114,8 +114,10 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P const orgsMap = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { withDomains: true }) + const memberOrgsWithDataAfterChange = orgsMap.get(memberId) ?? [] + const responseMo: IMemberRoleWithOrganization = groupMemberOrganizations( - orgsMap.get(memberId) ?? [], + memberOrgsWithDataAfterChange, ).find((mo) => mo.id === workExperienceId) ?? { ...workExperienceWithOrgData, ...updatedMemberOrg, From 5bd71f2d0fb58c2d404fe71aade55018b0cb0ef7 Mon Sep 17 00:00:00 2001 From: Yeganathan S <63534555+skwowet@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:01:37 +0530 Subject: [PATCH 2/8] fix: remove unnecessary grouped lookup in verify work experience Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com> --- .../updateMemberWorkExperience.ts | 8 ++--- .../verifyMemberWorkExperience.ts | 33 ++++++------------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/backend/src/api/public/v1/members/work-experiences/updateMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/updateMemberWorkExperience.ts index ed23e35734..62ce2277f0 100644 --- a/backend/src/api/public/v1/members/work-experiences/updateMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/updateMemberWorkExperience.ts @@ -122,11 +122,9 @@ export async function updateMemberWorkExperience(req: Request, res: Response): P const orgsMap = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { withDomains: true }) - const memberOrgsWithData = orgsMap.get(memberId) ?? [] - - const updatedMo = - groupMemberOrganizations(memberOrgsWithData).find((mo) => mo.id === workExperienceId) ?? - memberOrgsWithData.find((mo) => mo.id === workExperienceId) + const updatedMo = groupMemberOrganizations(orgsMap.get(memberId) ?? []).find( + (mo) => mo.id === workExperienceId, + ) if (!updatedMo) { throw new NotFoundError('Work experience not found') diff --git a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts index 0dc9c7cde6..d1c3fd9a11 100644 --- a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts @@ -52,18 +52,6 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P throw new NotFoundError('Work experience not found') } - const orgsMapBeforeChange = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { - withDomains: true, - }) - - const memberOrgsWithData = orgsMapBeforeChange.get(memberId) ?? [] - - const workExperienceWithOrgData = memberOrgsWithData.find((mo) => mo.id === workExperienceId) - - if (!workExperienceWithOrgData) { - throw new NotFoundError('Work experience not found') - } - const overlappingGroupedRows = getOverlappingGroupedMemberOrganizations(memberOrgs, memberOrg) const memberOrgIdsToDelete = [ @@ -113,17 +101,16 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P ) const orgsMap = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { withDomains: true }) - - const memberOrgsWithDataAfterChange = orgsMap.get(memberId) ?? [] - - const responseMo: IMemberRoleWithOrganization = groupMemberOrganizations( - memberOrgsWithDataAfterChange, - ).find((mo) => mo.id === workExperienceId) ?? { - ...workExperienceWithOrgData, - ...updatedMemberOrg, - verified, - verifiedBy, - } + const memberOrgsWithData = orgsMap.get(memberId) ?? [] + + const responseMo: IMemberRoleWithOrganization = + groupMemberOrganizations(memberOrgsWithData).find((mo) => mo.id === workExperienceId) ?? + ({ + ...(memberOrgsWithData.find((mo) => mo.id === workExperienceId) ?? memberOrg), + ...updatedMemberOrg, + verified, + verifiedBy, + } as IMemberRoleWithOrganization) ok(res, toMemberWorkExperience(responseMo)) } From 973aae5ff733c5357cb06dd7afe20107f3dd7b83 Mon Sep 17 00:00:00 2001 From: Yeganathan S <63534555+skwowet@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:17:25 +0530 Subject: [PATCH 3/8] fix: enhance work experience verification with fallback organization data Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com> --- .../verifyMemberWorkExperience.ts | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts index d1c3fd9a11..7022100068 100644 --- a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts @@ -52,6 +52,17 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P throw new NotFoundError('Work experience not found') } + // Stash org fields for response fallback when reject soft-deletes the row. + const orgsMapBeforeChange = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { + withDomains: true, + }) + + const memberOrgsWithOrgDataBeforeChange = orgsMapBeforeChange.get(memberId) ?? [] + + const workExperienceWithOrgDataBeforeChange = memberOrgsWithOrgDataBeforeChange.find( + (mo) => mo.id === workExperienceId, + ) + const overlappingGroupedRows = getOverlappingGroupedMemberOrganizations(memberOrgs, memberOrg) const memberOrgIdsToDelete = [ @@ -103,14 +114,22 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P const orgsMap = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { withDomains: true }) const memberOrgsWithData = orgsMap.get(memberId) ?? [] - const responseMo: IMemberRoleWithOrganization = - groupMemberOrganizations(memberOrgsWithData).find((mo) => mo.id === workExperienceId) ?? - ({ - ...(memberOrgsWithData.find((mo) => mo.id === workExperienceId) ?? memberOrg), - ...updatedMemberOrg, - verified, - verifiedBy, - } as IMemberRoleWithOrganization) + const fallbackMo = + memberOrgsWithData.find((mo) => mo.id === workExperienceId) ?? + workExperienceWithOrgDataBeforeChange + + if (!fallbackMo) { + throw new NotFoundError('Work experience not found') + } + + const responseMo: IMemberRoleWithOrganization = groupMemberOrganizations(memberOrgsWithData).find( + (mo) => mo.id === workExperienceId, + ) ?? { + ...fallbackMo, + ...updatedMemberOrg, + verified, + verifiedBy, + } ok(res, toMemberWorkExperience(responseMo)) } From 38bdf05aee2bc2343c884ad08ed84442c17bddae Mon Sep 17 00:00:00 2001 From: Yeganathan S <63534555+skwowet@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:27:27 +0530 Subject: [PATCH 4/8] fix: include grouped organization fallback in work experience verification Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com> --- .../v1/members/work-experiences/verifyMemberWorkExperience.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts index 7022100068..99f072fff0 100644 --- a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts @@ -113,9 +113,11 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P const orgsMap = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { withDomains: true }) const memberOrgsWithData = orgsMap.get(memberId) ?? [] + const groupedMemberOrgsBeforeChange = groupMemberOrganizations(memberOrgsWithOrgDataBeforeChange) const fallbackMo = memberOrgsWithData.find((mo) => mo.id === workExperienceId) ?? + groupedMemberOrgsBeforeChange.find((mo) => mo.id === workExperienceId) ?? workExperienceWithOrgDataBeforeChange if (!fallbackMo) { From e52455383b0f4400dd41f6f0bd9715f13578466f Mon Sep 17 00:00:00 2001 From: Yeganathan S <63534555+skwowet@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:38:51 +0530 Subject: [PATCH 5/8] fix: streamline work experience verification with new resolution function Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com> --- .../verifyMemberWorkExperience.ts | 65 ++++++++++++------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts index 99f072fff0..e3fd312e43 100644 --- a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts @@ -33,6 +33,21 @@ const bodySchema = z.object({ verifiedBy: z.string(), }) +function resolveWorkExperience( + workExperienceId: string, + ...collections: IMemberRoleWithOrganization[][] +): IMemberRoleWithOrganization | undefined { + for (const collection of collections) { + const match = collection.find((mo) => mo.id === workExperienceId) + + if (match) { + return match + } + } + + return undefined +} + export async function verifyMemberWorkExperience(req: Request, res: Response): Promise { const { memberId, workExperienceId } = validateOrThrow(paramsSchema, req.params) const { verified, verifiedBy } = validateOrThrow(bodySchema, req.body) @@ -53,22 +68,21 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P } // Stash org fields for response fallback when reject soft-deletes the row. - const orgsMapBeforeChange = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { - withDomains: true, - }) + const memberOrgsWithOrgDataBeforeChange = verified + ? [] + : (( + await fetchManyMemberOrgsWithOrgData(qx, [memberId], { + withDomains: true, + }) + ).get(memberId) ?? []) - const memberOrgsWithOrgDataBeforeChange = orgsMapBeforeChange.get(memberId) ?? [] + const overlappingGroupedRows = getOverlappingGroupedMemberOrganizations(memberOrgs, memberOrg) - const workExperienceWithOrgDataBeforeChange = memberOrgsWithOrgDataBeforeChange.find( - (mo) => mo.id === workExperienceId, + const overlappingRowsWithIds = overlappingGroupedRows.filter( + (row): row is typeof row & { id: string } => !!row.id, ) - const overlappingGroupedRows = getOverlappingGroupedMemberOrganizations(memberOrgs, memberOrg) - - const memberOrgIdsToDelete = [ - workExperienceId, - ...overlappingGroupedRows.flatMap((row) => (row.id ? [row.id] : [])), - ] + const memberOrgIdsToDelete = [workExperienceId, ...overlappingRowsWithIds.map((row) => row.id)] const verifiedUpdate = { verified, verifiedBy } @@ -89,9 +103,7 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P verifiedUpdate, ) - for (const overlappingRow of overlappingGroupedRows.filter( - (row): row is typeof row & { id: string } => !!row.id, - )) { + for (const overlappingRow of overlappingRowsWithIds) { await updateMemberOrganization(tx, memberId, overlappingRow.id, verifiedUpdate) } } else { @@ -107,30 +119,35 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P }) } - captureNewState(updatedMemberOrg ?? { ...memberOrg, verified, verifiedBy }) + captureNewState(updatedMemberOrg ?? { ...memberOrg, ...verifiedUpdate }) }), ) - const orgsMap = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { withDomains: true }) + const orgsMap = await fetchManyMemberOrgsWithOrgData(qx, [memberId], { + withDomains: true, + }) + const memberOrgsWithData = orgsMap.get(memberId) ?? [] + const groupedMemberOrgs = groupMemberOrganizations(memberOrgsWithData) const groupedMemberOrgsBeforeChange = groupMemberOrganizations(memberOrgsWithOrgDataBeforeChange) - const fallbackMo = - memberOrgsWithData.find((mo) => mo.id === workExperienceId) ?? - groupedMemberOrgsBeforeChange.find((mo) => mo.id === workExperienceId) ?? - workExperienceWithOrgDataBeforeChange + const fallbackMo = resolveWorkExperience( + workExperienceId, + memberOrgsWithData, + groupedMemberOrgsBeforeChange, + memberOrgsWithOrgDataBeforeChange, + ) if (!fallbackMo) { throw new NotFoundError('Work experience not found') } - const responseMo: IMemberRoleWithOrganization = groupMemberOrganizations(memberOrgsWithData).find( + const responseMo: IMemberRoleWithOrganization = groupedMemberOrgs.find( (mo) => mo.id === workExperienceId, ) ?? { ...fallbackMo, ...updatedMemberOrg, - verified, - verifiedBy, + ...verifiedUpdate, } ok(res, toMemberWorkExperience(responseMo)) From 9923101ba6cb674068be087e4d30d50900d23e2b Mon Sep 17 00:00:00 2001 From: Yeganathan S <63534555+skwowet@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:05:13 +0530 Subject: [PATCH 6/8] refactor: no need to handle edge cases with hidden mo id Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com> --- .../verifyMemberWorkExperience.ts | 41 ++++--------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts index e3fd312e43..fe7327c5cc 100644 --- a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts @@ -33,21 +33,6 @@ const bodySchema = z.object({ verifiedBy: z.string(), }) -function resolveWorkExperience( - workExperienceId: string, - ...collections: IMemberRoleWithOrganization[][] -): IMemberRoleWithOrganization | undefined { - for (const collection of collections) { - const match = collection.find((mo) => mo.id === workExperienceId) - - if (match) { - return match - } - } - - return undefined -} - export async function verifyMemberWorkExperience(req: Request, res: Response): Promise { const { memberId, workExperienceId } = validateOrThrow(paramsSchema, req.params) const { verified, verifiedBy } = validateOrThrow(bodySchema, req.body) @@ -127,27 +112,19 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P withDomains: true, }) - const memberOrgsWithData = orgsMap.get(memberId) ?? [] - const groupedMemberOrgs = groupMemberOrganizations(memberOrgsWithData) + const groupedMemberOrgs = groupMemberOrganizations(orgsMap.get(memberId) ?? []) const groupedMemberOrgsBeforeChange = groupMemberOrganizations(memberOrgsWithOrgDataBeforeChange) - const fallbackMo = resolveWorkExperience( - workExperienceId, - memberOrgsWithData, - groupedMemberOrgsBeforeChange, - memberOrgsWithOrgDataBeforeChange, - ) + const fallbackMo = groupedMemberOrgsBeforeChange.find((mo) => mo.id === workExperienceId) - if (!fallbackMo) { - throw new NotFoundError('Work experience not found') - } + const responseMo: IMemberRoleWithOrganization = + groupedMemberOrgs.find((mo) => mo.id === workExperienceId) ?? + (fallbackMo + ? { ...fallbackMo, ...updatedMemberOrg, ...verifiedUpdate } + : undefined) - const responseMo: IMemberRoleWithOrganization = groupedMemberOrgs.find( - (mo) => mo.id === workExperienceId, - ) ?? { - ...fallbackMo, - ...updatedMemberOrg, - ...verifiedUpdate, + if (!responseMo) { + throw new NotFoundError('Work experience not found') } ok(res, toMemberWorkExperience(responseMo)) From b03256b946f8ca21e02f60e6fc42aca2c9da5746 Mon Sep 17 00:00:00 2001 From: Yeganathan S <63534555+skwowet@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:05:53 +0530 Subject: [PATCH 7/8] fix: make prettier and linter happy Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com> --- .../v1/members/work-experiences/verifyMemberWorkExperience.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts index fe7327c5cc..a175f87e54 100644 --- a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts @@ -119,9 +119,7 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P const responseMo: IMemberRoleWithOrganization = groupedMemberOrgs.find((mo) => mo.id === workExperienceId) ?? - (fallbackMo - ? { ...fallbackMo, ...updatedMemberOrg, ...verifiedUpdate } - : undefined) + (fallbackMo ? { ...fallbackMo, ...updatedMemberOrg, ...verifiedUpdate } : undefined) if (!responseMo) { throw new NotFoundError('Work experience not found') From 4d4ed5c6992f4bb314cf022ade319c072aefdd89 Mon Sep 17 00:00:00 2001 From: Yeganathan S <63534555+skwowet@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:34:57 +0530 Subject: [PATCH 8/8] fix: resolve pr review comments Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com> --- .../v1/members/work-experiences/verifyMemberWorkExperience.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts index a175f87e54..be85eca166 100644 --- a/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts +++ b/backend/src/api/public/v1/members/work-experiences/verifyMemberWorkExperience.ts @@ -119,7 +119,7 @@ export async function verifyMemberWorkExperience(req: Request, res: Response): P const responseMo: IMemberRoleWithOrganization = groupedMemberOrgs.find((mo) => mo.id === workExperienceId) ?? - (fallbackMo ? { ...fallbackMo, ...updatedMemberOrg, ...verifiedUpdate } : undefined) + (fallbackMo ? { ...fallbackMo, ...verifiedUpdate } : undefined) if (!responseMo) { throw new NotFoundError('Work experience not found')