Commit Graph

24 Commits

Author SHA1 Message Date
neo773 712b1553bd Fix participant matching failing due to updating all columns instead of only changed fields (#18105)
The updateMany in matchParticipants was spreading the entire participant
object into the SET clause, which included generated columns
(searchVector) and composite field columns (createdBySource) that can't
be written to. Narrowed the update to only set personId and
workspaceMemberId.
```
[1] query failed: UPDATE "workspace_3ixj3i1a5avy16ptijtb3lae3"."calendarEventParticipant" SET "id" = $1, "createdAt" = $2, "updatedAt" = $3, "deletedAt" = $4, "createdBySource" = $5, "createdByWorkspaceMemberId" = $6, "createdByName" = $7, "createdByContext" = $8, "updatedBySource" = $9, "updatedByWorkspaceMemberId" = $10, "updatedByName" = $11, "updatedByContext" = $12, "position" = $13, "searchVector" = $14, "handle" = $15, "displayName" = $16, "isOrganizer" = $17, "responseStatus" = $18, "calendarEventId" = $19, "personId" = $20, "workspaceMemberId" = $21 WHERE "id" = $22 RETURNING * -- PARAMETERS: ["f1526103-451a-429f-9743-3a81c3a3e3aa","2026-02-19T22:23:32.354Z","2026-02-19T22:23:32.354Z",null,"MANUAL",null,"System",null,"MANUAL",null,"System",null,0,"'test@test.com':1","test@test.com","",false,"NEEDS_ACTION","fb1892a8-6daf-435b-a43b-e8fe8693eb99","60bf9e82-f1b7-4bed-a1af-7039fb9c32f5",null,"f1526103-451a-429f-9743-3a81c3a3e3aa"]
[1] error: error: column "searchVector" can only be updated to DEFAULT
[1] Exception Captured
[1]   undefined
[1]   [
[1]     PostgresException [Error]: Data validation error.
[1]         at computeTwentyORMException (/Users/huzef/Documents/bounties/twenty/packages/twenty-server/dist/engine/twenty-orm/error-handling/compute-twenty-orm-exception.js:35:19)
[1]         at WorkspaceUpdateQueryBuilder.executeMany (/Users/huzef/Documents/bounties/twenty/packages/twenty-server/dist/engine/twenty-orm/repository/workspace-update-query-builder.js:269:82)
[1]         at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
[1]         at async WorkspaceRepository.updateMany (/Users/huzef/Documents/bounties/twenty/packages/twenty-server/dist/engine/twenty-orm/repository/workspace.repository.js:234:25)
[1]         at async MatchParticipantService.matchParticipants (/Users/huzef/Documents/bounties/twenty/packages/twenty-server/dist/modules/match-participant/match-participant.service.js:93:13)
[1]         at async /Users/huzef/Documents/bounties/twenty/packages/twenty-server/dist/modules/match-participant/match-participant.service.js:160:13
[1]         at async MatchParticipantService.matchParticipantsForPeople (/Users/huzef/Documents/bounties/twenty/packages/twenty-server/dist/modules/match-participant/match-participant.service.js:130:9)
[1]         at async CalendarEventParticipantMatchParticipantJob.handle (/Users/huzef/Documents/bounties/twenty/packages/twenty-server/dist/modules/calendar/calendar-event-participant-manager/jobs/calendar-event-participant-match-participant.job.js:45:13)
[1]         at async MessageQueueExplorer.invokeProcessMethods (/Users/huzef/Documents/bounties/twenty/packages/twenty-server/dist/engine/core-modules/message-queue/message-queue.explorer.js:113:17)
[1]         at async MessageQueueExplorer.handleProcessor (/Users/huzef/Documents/bounties/twenty/packages/twenty-server/dist/engine/core-modules/message-queue/message-queue.explorer.js:104:13) {
[1]       code: '428C9'
[1]     }
[1]   ]
```
2026-02-20 10:25:10 +01:00
Weiko 2daebc6d0f Add WorkspaceAuthContextMiddleware (#17487)
## Context
Introduces a middleware that automatically sets the workspace auth
context in AsyncLocalStorage for HTTP requests, making it available
throughout the request lifecycle without explicit parameter passing.

The motivation behind this change is to reduce boilerplate and simplify
the developer experience when working with workspace data in HTTP
request handlers.

The Problem (Before)
Every HTTP request handler that needed to access workspace data had to:
- Extract auth-related info from decorators (@AuthWorkspace(),
@AuthUserWorkspaceId(), etc.) in controller/resolver and pass down to
services
- Build or pass the authContext explicitly (sometimes with type
assertion which was flaky)
Then call executeInWorkspaceContext(authContext, async () => { ... })

## Changes
- Add WorkspaceAuthContextMiddleware that extracts auth context from the
request and stores it in AsyncLocalStorage
- Register middleware for GraphQL, metadata, and REST routes (runs after
hydration middlewares)
- Simplify executeInWorkspaceContext signature: fn is now the first
parameter, authContext is optional second
- If authContext is not provided, it's automatically retrieved from the
storage (set by middleware)
- Update all callers (~120 files) to use the new parameter order


- Fixes a bug in search where system auth context was used, bypassing
RLS feature.
2026-01-27 17:24:51 +00:00
Abdullah. 2c8d3f02e1 feat: upgrade to Storybook version 10 (#17110)
Upgraded to Storybook 10. We still use `@storybook/test-runner` for
testing since it appears it'd require more work to move from Jest to
Vitest than I initially anticipated, but I completed this PR to fix
`storybook:serve:dev` - it takes time to load, but it works the way it
used to with Storybook 8.


https://github.com/user-attachments/assets/7afc32c6-4bcf-4b37-b83b-8d00d28dda15
2026-01-13 08:18:07 +00:00
Weiko 9bd8f94b3a Refactor global datasource part 3 (#16447)
## Context
Following https://github.com/twentyhq/twenty/pull/16399
Now using the new global orm manager everywhere and returning a
GlobalDatasource/WorkspaceDatasource based on a feature flag.
This means we now need to wrap all our ORM calls within
executeInWorkspaceContext callback (at least for now) so the global
datasource can dynamically hydrate its context via the new store (the
global datasource does not store anything related to workspaces as it is
now a unique singleton). If feature flag is off it still uses local data
stored in the workspace datasource.
2025-12-10 17:17:33 +01:00
Weiko 859004f4fc Refactor global datasource part 2 (#16399)
## Context
Deprecating TwentyORMManager in favor of TwentyORMGlobalManager
(temporarily, as this will simplify the ultimate goal to later replace
all usages with the new TwentyORMGlobalManagerV2 which will have a
similar signature)
This means this PR had to refactor a bit of code to pass down the
workspaceId when not available directly as it is now a requirement,
meaning we also deprecated scopedWorkspaceContextFactory to have a less
obscure way to fetch the workspaceId and have something more
declarative.

Step 3 will be to update TwentyORMGlobalManager to use a featureFlag
toggling and use the new GlobalWorkspaceOrmManager internally using the
new cache service

Step 4 will be to remove the feature flag and pg_pool patch
2025-12-08 17:05:00 +01:00
Charles Bochet eb362c6d5f Update workspace entities to make all TEXT nullable (#16144)
Follow up on #15926

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
Co-authored-by: guillim <guigloo@msn.com>
2025-11-28 10:50:38 +01:00
Marie 0975b06a9b [demo] Allow workspace to work with a non-system workspaceMember object (#15547)
For demo purposes, we want to work with workspaceMember has a non-system
object, allowing it to be displayed on the product, to be added custom
fields etc.
It is something we may want to do later anyway. 
This PR adds a bypassPermissionChecks on workspaceMember repository
calls. This does not provide more permissions than before for other
workspaces: workspaceMember being a system object, permissions are
already bypassed for this one. (Note that actions such inviting a new
workspaceMember, updating a workspaceMember are protected by a system
permission checked in the relevant places).

This work does **not** allow any workspace to switch their
workspaceMember object to non-system, the switch is still manual.
2025-11-03 14:57:37 +01:00
Félix Malfait c5564d9bd0 [BREAKING CHANGE] refactor: Add Entity suffix to TypeORM entity classes (#15239)
## Summary

This PR refactors all TypeORM entity classes in the Twenty codebase to
include an 'Entity' suffix (e.g., User → UserEntity, Workspace →
WorkspaceEntity) to improve code clarity and follow TypeORM naming
conventions.

## Changes

### Entity Renaming
-  Renamed **57 core TypeORM entities** with 'Entity' suffix
-  Updated all related imports, decorators, and type references
-  Fixed Repository<T>, @InjectRepository(), and
TypeOrmModule.forFeature() patterns
-  Fixed @ManyToOne/@OneToMany/@OneToOne decorator references

### Backward Compatibility
-  Preserved GraphQL schema names using @ObjectType('OriginalName')
decorators
-  **No breaking changes** to GraphQL API
-  **No database migrations** required
-  File names unchanged (user.entity.ts remains as-is)

### Code Quality
-  Fixed **497 TypeScript errors** (82% reduction from 606 to 109)
-  **All linter checks passing**
-  Improved type safety across the codebase

## Entities Renamed

```
User → UserEntity
Workspace → WorkspaceEntity
ApiKey → ApiKeyEntity
AppToken → AppTokenEntity
UserWorkspace → UserWorkspaceEntity
Webhook → WebhookEntity
FeatureFlag → FeatureFlagEntity
ApprovedAccessDomain → ApprovedAccessDomainEntity
TwoFactorAuthenticationMethod → TwoFactorAuthenticationMethodEntity
WorkspaceSSOIdentityProvider → WorkspaceSSOIdentityProviderEntity
EmailingDomain → EmailingDomainEntity
KeyValuePair → KeyValuePairEntity
PublicDomain → PublicDomainEntity
PostgresCredentials → PostgresCredentialsEntity
...and 43 more entities
```

## Impact

### Files Changed
- **400 files** modified
- **2,575 insertions**, **2,191 deletions**

### Progress
-  **82% complete** (497/606 errors fixed)
- ⚠️ **109 TypeScript errors** remain (18% of original)

## Remaining Work

The 109 remaining TypeScript errors are primarily:

1. **Function signature mismatches** (~15 errors) - Test mocks with
incorrect parameter counts
2. **Entity type mismatches** (~25 errors) - UserEntity vs
UserWorkspaceEntity confusion
3. **Pre-existing issues** (~50 errors) - Null safety and DTO
compatibility (unrelated to refactoring)
4. **Import type issues** (~10 errors) - Entities imported with 'import
type' but used as values
5. **Minor decorator issues** (~9 errors) - onDelete property
configurations

These can be addressed in follow-up PRs without blocking this
refactoring.

## Testing Checklist

- [x] Linter passing
- [ ] Unit tests should be run (CI will verify)
- [ ] Integration tests should be run (CI will verify)
- [ ] Manual testing recommended for critical user flows

## Breaking Changes

**None** - This is a pure refactoring with full backward compatibility:
- GraphQL API unchanged (uses original entity names)
- Database schema unchanged
- External APIs unchanged

## Notes

- Created comprehensive `REFACTORING_STATUS.md` documenting the entire
process
- All temporary scripts have been cleaned up
- Branch: `refactor/add-entity-suffix-to-typeorm-entities`

## Reviewers

Please review especially:
- Entity renaming patterns
- GraphQL backward compatibility
- Any areas where entity types are confused (UserEntity vs
UserWorkspaceEntity)

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-10-22 09:55:20 +02:00
Etienne 560e24fa4b Update unique fields on standard field - include soft deleted records (#14562)
Done : 
- migrate standard unique fields (add : -old)
- deactivate defaultWhereClause
- restore soft deleted if upserted (same for contact creation in mailing
sync)

fixes https://github.com/twentyhq/twenty/issues/14443

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-10-11 15:50:29 +02:00
neo773 ad944e1d2c merge records composite type (#14005)
/closes #13989

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-09-08 17:50:26 +02:00
Félix Malfait 8b4b9ef8da Change type import rule (#13751)
Forcing "type" to be explicit, works best will rollup on the frontend to
exclude depdendencies
2025-08-08 01:27:05 +02:00
Charles Bochet dc3c194f3e Improve messaging sync performances (#13549)
This PR aims to improve performances as we are making A LOT of queries
after having added events emission to the ORM layer. While investigating
issues, I've come across multiple problems I will describe below

## Add index on workspace.activationStatus as we are querying it a lot

As per title

## Add logs on core datasource destroy

It seems that we have postgres connection pool destruction in
production. I cannot reproduce locally but I suspect the Query Timeouts
to be the root cause. I'm fixing most of the Query Timeouts cause in
this PR but I'm adding the logs so we have more information in case in
keeps happening in production.

## GraphQL query runner createMany

It was using a for loop on each record. This is as issue has we will
emit an event separately for each record => we should always try to
batch events.
Replacing by a save on all records. Note that this is not perfect as we
should avoid using save (bad performances), and use insert + updateMany
instead. As I have follow up discussions regarding permissions, I
haven't replaced it by insert and updateMany yet. Using save instead of
a for loop makes the problem less worrying.

## Introduce updateMany in ORM @Weiko @ijreilly FYI

.save(manyRecords) is bad as it's querying the data for no good reason
(and doing a select for each record...).
We already have .insert(), i'm introducing .updateMany()

I think our ORM layer should be simplified a lot but I'm not starting
the refacto yet

## Fixing ORM @Weiko @ijreilly  FYI
- Fixing events emission in delete function
- Fixing events emission in insert function
- make sure everything is batched

## Events performance @Weiko @ijreilly FYI

Do not emit timelineActivity db events as this does not seem useful and
is quite heavy

## Messaging and Calendar performance @bosiraphael FYI

Rework many functions to make sure they are batched. This does not touch
the driver layer and I have heavily tested it. (multiple account, with
multiple channels, common thread, common messages, etc...)

## Workflow Trigger relation Fetch performance @martmull FYI

Improved performance by batching
2025-08-03 23:56:44 +02:00
Weiko 2deac9448e Add db event emitter in twenty orm (#13167)
## Context
Add an eventEmitter instance to twenty datasources so we can emit DB
events.
Add input and output formatting to twenty orm (formatData, formatResult)
Those 2 elements simplified existing logic when we interact with the
ORM, input will be formatted by the ORM so we can directly use
field-like structure instead of column-like. The output will be
formatted, for builder queries it will be in `result.generatedMaps`
where `result.raw` preserves the previous column-like structure.

Important change: We now have an authContext that we can pass when we
get a repository, this will be used for the different events emitted in
the ORM. We also removed the caching for repositories as it was not
scaling well and not necessary imho

Note: An upcoming PR should handle the onDelete: cascade behavior where
we send DESTROY events in cascade when there is an onDelete: CASCADE on
the FK.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-07-17 18:07:28 +02:00
Marie beba4b8313 Add missing overrides on entityManager (#12471)
In this PR

1. Add missing override of insert() method on
WorkspaceSelectQueryBuilder to return our custom
WorkspaceInsertQueryBuilder with permission checks.
2. Replace override implementation of methods on WorkspaceEntityManager
that call createQueryBuilder at a nested internal layer of typeORM (i.e.
not directly in the initial implementation of EntityManager - unlike
findBy for instance -, but in calls done under the hood at a level which
would force us to override entire other classes to pass on our
permissionOptions. It is the case for methods which call typeORM's
EntityPersistExecutor for instance.), to validate permissions and then
allow the subsequent calls to be made without permission checks
3. adapt tests

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-06-11 12:50:10 +02:00
Raphaël Bosi eed9125945 Improved participant matching with additional emails support (#12368)
# Improved participant matching with additional emails support

Closes #8991 

This PR extends the participant matching system to support additional
emails in addition to primary emails for both calendar events and
messages. Previously, the system only matched participants based on
primary emails, missing matches with secondary email addresses.

- Contact creation now consider both primary and additional emails when
checking for existing contacts
- Calendar and message participant listeners now handle both primary and
additional email changes
- Added tests

## To test this PR:

Check that:
- Primary emails take precedence over additional emails in matching
- Case-insensitive email comparisons work correctly
- A contact is not created if a person already exists with the email as
its additional email
- Event listeners handle both creation and update scenarios
- Matching and unmatching logic works for complex email change scenarios
- When unmatching after a change in a primary or secondary email, events
and messages should be rematched if another person has this email as its
primary or secondary email.

---------

Co-authored-by: guillim <guigloo@msn.com>
2025-06-03 14:36:56 +02:00
Marie a9e73c6340 [permissions] Add permissions check layer in entityManager (#11818)
First and main step of
https://github.com/twentyhq/core-team-issues/issues/747

We are implementing a permission check layer in our custom
WorkspaceEntityManager by overriding all the db-executing methods (this
PR only overrides some as a POC, the rest will be done in the next PR).
Our custom repositories call entity managers under the hood to interact
with the db so this solves the repositories case too.
This is still behind the feature flag IsPermissionsV2Enabled.

In the next PR
- finish overriding all the methods required in WorkspaceEntityManager
- add tests
2025-05-05 14:06:54 +00:00
Raphaël Bosi 743169a260 Fix message participant assignation bug (#8857)
Closes #8846
2024-12-03 23:27:08 +01:00
martmull 39373b4a28 8643 fix sentry error (#8644)
- fixes missing data in event payload when adding a new workspaceMember
- add strong typing to database event emitters
2024-11-21 16:09:36 +00:00
Charles Bochet a58236e6da Remove deprecated EMAIL, PHONE, LINK (#7551)
In this PR:
- remove deprecated EMAIL, PHONE, LINK field types (except for Zapier
package as there is another work ongoing)
- remove composite currency filter on currencyCode, actor filter on name
and workspaceMember as the UX is not great yet
2024-10-10 14:14:58 +02:00
gitstart-app[bot] 31c02202bd Handle migration of Email to Emails fields (#6885)
This is the second PR on TWNTY-6261 which handlesdata migration of Email
field to Emails field.\
\
How to Test?\
Firstly make sure that you have completed the testing steps on first PR
then follow the below steps:

- Checkout to TWNTY-6261-emails-migrations branch
- Rebuild typescript using "npx nx build twenty-server"
- Run command "yarn command:prod upgrade-0.25" to do migration\
  \
  Loom Video:\

<https://www.loom.com/share/f82b8d29f8f64f92abe3c59c01147b45?sid=9f8ccc05-aa38-4c49-b139-fd0823066273>

**Testing Messaging Sync functionality:**

Please watch the below video to see that the synchronization of contacts
is working fine after migrating Email field to Emails field:\

<https://www.loom.com/share/400949464b244272b78c25e338cc6ab2?sid=103f6625-5933-4b99-9825-0fed33782f36>

**Question to the client**

should we rename email to emails here? in the DomainName PR, the name
did not change.

```typescript
  @WorkspaceField({
    standardId: PERSON_STANDARD_FIELD_IDS.email,
    type: FieldMetadataType.EMAILS,
    label: 'Email',
    description: 'Contact’s Email',
    icon: 'IconMail',
  })
  email: EmailsMetadata;
```

**Test Messaging Sync**

This pr will update messaging sync files so the changes shouldn't break
existing functionality of importing people and companies in the app.\
To test messaging sync you should follow the below steps:\
1. you need to connect a google account to see the importing
functionality. For this purpose you

have to create a project inside Google Cloud. But to make things easier
you can use the below credentials of an already created project. Put
them in .env of twenty-server package:

```properties
MESSAGING_PROVIDER_GMAIL_ENABLED=true
CALENDAR_PROVIDER_GOOGLE_ENABLED=true
AUTH_GOOGLE_ENABLED=true
AUTH_GOOGLE_CLIENT_ID=951231465939-h61tg6nkpkv1821qi899fjbj9looquto.apps.googleusercontent.com
AUTH_GOOGLE_CLIENT_SECRET=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
AUTH_GOOGLE_CALLBACK_URL=http://localhost:3000/auth/google/redirect
AUTH_GOOGLE_APIS_CALLBACK_URL=http://localhost:3000/auth/google-apis/get-access-token
MESSAGE_QUEUE_TYPE=bull-mq
```

Alternative env

```properties
MESSAGING_PROVIDER_GMAIL_ENABLED=true
CALENDAR_PROVIDER_GOOGLE_ENABLED=true
AUTH_GOOGLE_ENABLED=true
AUTH_GOOGLE_CLIENT_ID=622006708006-dc4n3vrtf3cs2h6k7hgbborudme7ku9l.apps.googleusercontent.com
AUTH_GOOGLE_CLIENT_SECRET=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
AUTH_GOOGLE_CALLBACK_URL=http://localhost:3000/auth/google/redirect
AUTH_GOOGLE_APIS_CALLBACK_URL=http://localhost:3000/auth/google-apis/get-access-token
MESSAGE_QUEUE_TYPE=bull-mq
```

1. Launch your worker with `npx nx run twenty-server:worker`
2. npx nx run twenty-server:command cron:messaging:messages-import
3. npx nx run twenty-server:command cron:messaging:message-list-fetch
4. npx nx run twenty-server:command
cron:calendar:calendar-event-list-fetch
5. Run the app and navigate to Settings/Accounts then connect your
Google account

---------

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
Co-authored-by: Marie Stoppa <marie.stoppa@essec.edu>
Co-authored-by: Weiko <corentin@twenty.com>
2024-09-12 18:31:11 +02:00
Raphaël Bosi 81fa3f0c41 6256 refactor messaging module to remove all provider specific code and put it inside the drivers folders (#6721)
Closes #6256 
Closes #6257 
+ Create custom exceptions

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-27 18:14:45 +02:00
Raphaël Bosi 091c0f83be 6619 modify event emitter to emit an array of events (#6625)
Closes #6619

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-20 19:44:29 +02:00
martmull 7cd5427589 Fix onboarding status performance issues (#6512)
Updated the onboardingStatus computation to improve performances

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-04 00:33:33 +02:00
bosiraphael d0db3b765f 6255 move services from messaging common module into the correct module and refactor them (#6409)
Closes #6255 

- Move files from `messaging/common` into the correct module
- Remove common module between calendar and messaging
`calendar-messaging-participant-manager`
- Update and fix massaging and calendar participant matching
- Create `MatchParticipantModule`

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-07-27 12:29:02 +02:00