twentyhq / twenty

Building a modern alternative to Salesforce, powered by the community.
https://twenty.com
GNU Affero General Public License v3.0
15.69k stars 1.69k forks source link

Method to merge Duplicates #6276

Open aficiomaquinas opened 1 month ago

aficiomaquinas commented 1 month ago

Scope & Context

I'm submitting a feature request for enabling users to merge duplicate person records in their workspace. This feature is important for maintaining clean and accurate data, especially in cases where partial information about a person is entered separately, resulting in duplicate records. The primary focus is on consolidating all related data, including the full history, opportunities, tasks, notes, and other relationships associated with each person record.

Current behavior

Currently, there is no built-in functionality to merge two person records. While users can manually copy basic information from one record to another, the main problem lies in consolidating the associated data:

This fragmentation of data leads to:

  1. Incomplete views of a person's history and relationships
  2. Potential loss of critical information if one record is deleted
  3. Inefficiencies in managing customer relationships with external systems via API
  4. Inaccurate reporting and analytics

Expected behavior

A comprehensive person merge feature that not only combines basic contact information but also consolidates all related data and maintains the full history of both records. This should be achievable through multiple interfaces: REST API, GraphQL, and User Interface.

The merge process should:

greptile-apps[bot] commented 1 month ago

Implementation Steps

  1. Create mergePersons Method in PersonService:

    • Path: /packages/twenty-server/src/workspace/messaging/repositories/person/person.service.ts
    • Add a new method mergePersons to handle merging person records.

      async mergePersons(primaryPersonId: string, secondaryPersonId: string, workspaceId: string, transactionManager?: EntityManager): Promise<void> {
      // Fetch both person records
      const primaryPerson = await this.getById(primaryPersonId, workspaceId, transactionManager);
      const secondaryPerson = await this.getById(secondaryPersonId, workspaceId, transactionManager);
      
      // Merge data from secondaryPerson into primaryPerson
      // Implement logic to handle merging of related entities (opportunities, tasks, notes, etc.)
      // Update references in related entities to point to primaryPerson
      
      // Delete secondaryPerson record
      await this.deletePerson(secondaryPersonId, workspaceId, transactionManager);
      }
  2. Update PersonRepository:

    • Path: /packages/twenty-server/src/modules/person/repositories/person.repository.ts
    • Add necessary methods to fetch, update, and delete person records.
      
      async getById(personId: string, workspaceId: string, transactionManager?: EntityManager): Promise<PersonWorkspaceEntity> {
      const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId);
      return await this.workspaceDataSourceService.executeRawQuery(`SELECT * FROM ${dataSourceSchema}.person WHERE id = $1`, [personId], workspaceId, transactionManager);
      }

    async deletePerson(personId: string, workspaceId: string, transactionManager?: EntityManager): Promise { const dataSourceSchema = this.workspaceDataSourceService.getSchemaName(workspaceId); await this.workspaceDataSourceService.executeRawQuery(DELETE FROM ${dataSourceSchema}.person WHERE id = $1, [personId], workspaceId, transactionManager); }

  3. Handle Merge Events in MessagingPersonListener:

    • Path: /packages/twenty-server/src/workspace/messaging/listeners/messaging-person.listener.ts
    • Add logic to handle events related to merging person records.
      async handleMergeEvent(payload: MergePersonEvent): Promise<void> {
      const { primaryPersonId, secondaryPersonId, workspaceId } = payload;
      await this.personService.mergePersons(primaryPersonId, secondaryPersonId, workspaceId);
      }
  4. Update GraphQL and REST API Endpoints:

    • Add new endpoints to trigger the merge functionality via API.
    • Ensure the endpoints call the mergePersons method in PersonService.
  5. Update Frontend to Support Merge Functionality:

    • Add UI components to allow users to select and merge person records.
    • Ensure the frontend calls the appropriate API endpoints to perform the merge.

References

/packages/twenty-server/src/workspace/messaging/repositories/person/person.service.ts /packages/twenty-server/src/modules/person/repositories/person.repository.ts /packages/twenty-server/src/modules/person/repositories/person/person.service.ts /packages/twenty-server/src/modules/connected-account/auto-companies-and-contacts-creation/services/create-company-and-contact.service.ts /packages/twenty-server/src/core/quick-actions/quick-actions.service.ts /packages/twenty-server/src/workspace/messaging/listeners/messaging-person.listener.ts /packages/twenty-chrome-extension/src/db/person.db.ts /packages/twenty-chrome-extension/src/graphql/person

#### About Greptile This response provides a starting point for your research, not a precise solution. Help us improve! Please leave a 👍 if this is helpful and 👎 if it is irrelevant. [Ask Greptile](https://app.greptile.com/chat/github/twentyhq/twenty/main) · [Edit Issue Bot Settings](https://app.greptile.com/apps/github)
aficiomaquinas commented 1 month ago

As I go further down the investigation on how to deduplicate persons in Twenty from my app through the API I think that it would be very useful to have company merging too.

FelixMalfait commented 1 month ago

Thanks for the suggestion! We always try to build features in the most agnostic way possible so if we build it for People, we would also build it for companies, opportunities or any custom object at the same time.

I think it's around 2 to 3 weeks or eng work to do this well. Backend is pretty simple (2 days?) but it would probably require significant frontend work (+ @Bonapara has not designed this, so it depends on how it'd look like)

Related: https://github.com/twentyhq/twenty/discussions/5244