Let's introduce an object-limited role for Tim, to test and/or spot
incompatibilities with restricted permissions in the future.
Our main user tim@apple.dev is now assigned a role that has all settings
permissions, and all object permissions except for update on Pets (to
test read-only view) and read on Rockets.
Since we still need an admin user for each workspace we are introducing
a new member, Jane, who has the admin role
---------
Co-authored-by: Félix Malfait <felix@twenty.com>
We were using a global ValidationPipe in main.ts. This is an issue as
@Controllers should return HttpExecption and @Resolvers should return
GraphqlErrors
Removing the global pipe and creating a ResolverValidationPipe able to
generate GraphqlError. We also need to handle the exception in a filter
to avoid nest to think it's unhandled and make it flow to logs
Next step:
- it would be nice to have both @UsePipes(ResolverValidationPipe) +
@UseFilters(GraphqlValidationExceptionFilter) come together. This should
be possible if we create a @GraphQLResolver annotation
In order to put back relations on track, we need to allow the
preexisting indexes to be created in indexmetadata, but also to avoid
failure when the migration runner will try to re-apply a pre-existing
index
- Fix an issue where custom object were seeded with 2 views, and with
the wrong icon
- ACME becomes YCombinator
- Allow 2 workspaces to have different metadata seeded
- Add many seeds for messages
- Add many seeds for calendar events
- Randomize createdBy for person and companies
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
# Introduction
close https://github.com/twentyhq/twenty/issues/12343
Adding a transform step for any field phone in order to infer country
code and calling code from the number if they're provided
## Edges cases
```ts
RecordTransformerExceptionCode.INVALID_PHONE_NUMBER:
RecordTransformerExceptionCode.INVALID_PHONE_COUNTRY_CODE:
RecordTransformerExceptionCode.CONFLICTING_PHONE_COUNTRY_CODE:
RecordTransformerExceptionCode.CONFLICTING_PHONE_CALLING_CODE:
RecordTransformerExceptionCode.CONFLICTING_PHONE_CALLING_CODE_AND_COUNTRY_CODE:
RecordTransformerExceptionCode.INVALID_PHONE_CALLING_CODE:
RecordTransformerExceptionCode.INVALID_URL:
```
## Coverage
Note: Will handle REST api integration testing pivot and UPDATE
operation later in the afternoon, critical bug appeared that I prefer
handling before improving this PR coverage, also would be too many
updates
Note2: Haven't fuzzed all of the string inputs, would seem overkill for
such a use case, to be debated
```ts
PASS test/integration/metadata/suites/field-metadata/phone/create-one-field-metadata-phone.integration-spec.ts (23.609 s)
Phone field metadata tests suite
✓ It should succeed create primary phone field (1397 ms)
✓ It should succeed create primary phone field with number and other information (930 ms)
✓ It should succeed create primary phone field with full international format and other information (893 ms)
✓ It should succeed create primary phone field with full international and infer other information from it but not the countryCode as its shared (825 ms)
✓ It should succeed create primary phone field with full international and infer other information from it (818 ms)
✓ It should succeed create primary phone field with empty payload (827 ms)
✓ It should succeed create additional phone field with number and other information (894 ms)
✓ It should succeed create additional phone field with full international format and other information (1024 ms)
✓ It should succeed create additional phone field with full international and infer other information from it but not the countryCode as its shared (808 ms)
✓ It should succeed create additional phone field with full international and infer other information from it (751 ms)
✓ It should succeed create additional phone field with empty payload (739 ms)
✓ It should fail to create primary phone field without country or calling code at all (776 ms)
✓ It should fail to create primary phone field with invalid country code (782 ms)
✓ It should fail to create primary phone field with invalid calling code (858 ms)
✓ It should fail to create primary phone field with conflicting country code and calling code (872 ms)
✓ It should fail to create primary phone field with invalid phone number format (1489 ms)
✓ It should fail to create primary phone field with conflicting phone number country code (1425 ms)
✓ It should fail to create primary phone field with conflicting phone number calling code (1553 ms)
✓ It should fail to create primary phone field without country or calling code at all (814 ms)
✓ It should fail to create primary phone field with invalid country code (813 ms)
✓ It should fail to create primary phone field with invalid calling code (742 ms)
✓ It should fail to create primary phone field with conflicting country code and calling code (783 ms)
✓ It should fail to create primary phone field with invalid phone number format (731 ms)
✓ It should fail to create primary phone field with conflicting phone number country code (947 ms)
✓ It should fail to create primary phone field with conflicting phone number calling code (822 ms)
Test Suites: 1 passed, 1 total
Tests: 25 passed, 25 total
Snapshots: 14 passed, 14 total
Time: 23.627 s
```
- Fixed an issue where you have invitations in your available workspaces
for signup.
- Corrected the URL display in the browser when hovering over the twenty
logo on the sign-in/up form.
- The workspace list is now displayed when you are logged into the
default domain.
## Why
After the changes on relations, index on relations were skipped by the
syncmetadata service, so no more migrations were generated for relation
fields.
We wanted to fix this.
## Test
This PR adds unit tests for the `createIndexMigration` utility in the
workspace migration builder. The tests cover:
- Creating index migrations for simple fields (e.g., text fields)
- Creating index migrations for relation fields (ensuring correct column
naming, e.g., `authorId` for the `author` objectmetadataname)
## Excluded
The delete index on relation does not need the column names so i don't
think i needed to work on this method. I might be wrong.
## Checklist
- [x] Added/updated unit tests for index migration creation
- [x] Verified correct handling of simple and relation fields
- [x] Ensured all tests pass
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
Fix inconsistent domain URL formats : removing the last / that was
caused by URL method
Standardize URL formatting to ensure consistent links storage and
retrieval of domain URLs across the application. Will improve the
dedpulicates in the links
Note: there is another temporary issue from google that was solved on
the 13th of june https://groups.google.com/g/adwords-api/c/tRSQMRZrJYM
but we consider this out of this scope
Fixes#12621
- Add seeds for notes/tasks
- Adds account manager to companies
- A companies and phone numbers to people
- Add many more opportunities
TODO: add timeline activities
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
## Context
Support button was missing for configuration having support enabled
(FrontApp)
<img width="1253" alt="image"
src="https://github.com/user-attachments/assets/930e3e0c-05a1-4a5b-820b-bb257f19fdde"
/>
## How
Recently, we changed some enums from lowercase to uppercase in graphql
## Problem resolution
supportDriver was typed as a string where we could have used
SupportDriver type. I'm exposing it in the graphql generated files to
re-use in the front so this issue cannot happen anymore
Closes https://github.com/twentyhq/core-team-issues/issues/992
Occasionaly, users can have a subscription created but still have their
workspace not activated and therefore not have a role yet, if they did
not go through the whole flow the first time. This causes a permission
check error while calling checkoutSession, while it shouldn't.
We detected the error through sentry. Since there has been no occurences
for the past three weeks in aggregateCompanies and getCurrentUser
transactions (while we have daily errors in checkoutSession), I assume
it has been fixed in the meantime. If not it will pop again on sentry
anyway !
<img width="798" alt="Capture d’écran 2025-06-16 à 18 38 43"
src="https://github.com/user-attachments/assets/2067c166-8b19-4c83-9270-6e49ee7ae0f5"
/>
## Goal
We have identified that sync-metadata (which is called during new
workspace initialization) is slow mainly because of workspaceMigration
application (migration-runner module). This is due to the fact that we
use typeORM API to perform schema changes, which often query the
existing schema. As querying the existing schema is costly (especially
with ~1M existing columns) and as we already have what we need described
as metadata, we will use raw SQL directly. This should divide the
workspace initialization time by x2.
## How
This PR can be read in two commits:
1. Extract functions tied to column migrations in a separate service
(`workspace-migration-column.service`) + deprecate COMMENT column
migration type which is not useful since we are not using pg-graphql
anymore
2. Re-work `workspace-migration-column.service` to make it clearer + use
raw SQL
## Result
Before:
<img width="1367" alt="image"
src="https://github.com/user-attachments/assets/e730df7b-db7f-4433-9ce5-52841b010990"
/>
After:
<img width="1367" alt="image"
src="https://github.com/user-attachments/assets/72d2c2b1-2475-4541-a3d5-50b70824a2e4"
/>
## Manual Testing
- Sync-metadata OK
- Workspace init OK
Closes https://github.com/twentyhq/core-team-issues/issues/868
We should not allow to grant any writing permission (update, soft
delete, delete) on an object or at role-level without the reading
permission at the same level.
This has been implemented in the front-end at role level, and is yet to
be done at object level (@Weiko)
We need to use twentyORMManager and not twentyORMGlobalManager in rest
api base handler, because we don't want to bypass permissions using
`shouldBypassPermissions` parameter (which we would have to do to use
twentyORMGlobalManager).
ScopedWorkspaceContextFactory was not adapted to rest api requests which
form differs from graphql request.
Update the default set of system fields for custom objects, to ensure
position is not nullabel and has a default value to 0
Steps to reproduce :
create a custom object,
send a POST request with body ```{position:null}```
the record should be created
After the change,
an error will be thrown
<img width="754" alt="Screenshot 2025-06-13 at 17 16 56"
src="https://github.com/user-attachments/assets/d40931f7-16cc-4b68-8dbb-deb0fa292be5"
/>
# Introduction
In a nutshell this PR introduces a `workspaceMemberEntity` to
`workspaceMemberDto` transpilation which was not done but commented as
`// TODO` across the `user resolver`.
Also passed on the `Roles` and `UserWorkspacePermissions` transpilation
We now also compute the roles for the `workspaceMember` resolver ( not
only the `workspaceMembers` )
Some refactor
In the following days about to create a PR that introduces integration
testing on the user resolver
## Conclusion
As always any suggestions are more than welcomed ! Please let me know !
## Misc
Following https://github.com/twentyhq/twenty/pull/11914
closing https://github.com/twentyhq/core-team-issues/issues/1011
Closes#12303
### What’s Changed
- Replace auto‐save with explicit Save / Cancel
Webhook forms now use manual “Save” and “Cancel” buttons instead of the
old debounced auto‐save/update.
- Separate “New” and “Detail” routes
Two dedicated paths `/settings/webhooks/new` for creation and
/`settings/webhooks/:webhookId` for editing, making the UX clearer.
- URL hint & normalization
If a user omits the http(s):// scheme, we display a “Will be saved as
https://…” hint and automatically default to HTTPS.
- Centralized validation with Zod
Introduced a `webhookFormSchema` for client‐side URL, operations, and
secret validation.
- Storybook coverage
Added stories for both “New Webhook” and “Webhook Detail”
- Unit tests
Added tests for the new `useWebhookForm` hook
If permissionsV2 feature flag is toggled, we should recompute the
permissions.
We decided to make each WorkspaceXxCacheService Xx-specific (feature
flag, permissions...), so we are not recomputing permission cache from
workspaceFeatureFlagCacheService where feature flags are recomputed,
even if that would be a lower level than FeatureFlagService. This allows
to avoid complex circuclar dependency and keeps a clear purpose for each
service.
In this PR
1. fix workflow step creation by adding forgotten
`shouldBypassPermissionChecks` in WorkflowVersionStepWorkspaceService
2. clarify the rule for twentyORMGlobalManager: do not add unnecessary
`shouldBypassPermissionChecks` for system objects (there are no
object-records permission checks on system objects, they are dealt with
at resolver level)
In this PR
- Determine object record permissions on workflows objects (workflow,
workflowVersion, workflowRun) base on settings permissions @Weiko
- Add Workflow permission guards on workflow resolvers @thomtrp . **Any
method within a resolver that has the SettingsPermission Guard is only
callable by a apiKey or a user that has the permission** (so not by
external parties).
- Add checks bypass in workflow services since 1) for actions gated by
settings permissions, the gate should be done at resolver level, so it
will have been done before the call to the service 2) some service
methods may be called by workflowTriggerController which is callable by
external parties without permissions (ex:
workflowCommonWorkspaceService.getWorkflowVersionOrFail). This is
something we may want to change in the future (still to discuss), by
removing the guard at resolver-level and relying on
shouldBypassPermissionChecks at getRepository and made in a way that we
only bypass for external parties.
- Add checks bypass for actions performed by workflows since they should
not be restricted in our current vision
- Add tests
# Fix cursor-based pagination with lexicographic ordering for composite
fields
## Bug
The existing cursor-based pagination implementation had a bug when
handling composite fields.
When paginating through results sorted by composite fields (like
`fullName` with sub-properties `firstName` and`lastName`), the WHERE
conditions generated for cursor positioning were incorrect, leading to
records being skipped.
The previous implementation was generating wrong WHERE conditions:
For example, when paginating with a cursor like `{ firstName: 'John',
lastName: 'Doe' }`, it would generate:
```sql
WHERE firstName > 'John' AND lastName > 'Doe'
```
This is incorrect because it would miss records like `{ firstName:
'John', lastName: 'Smith' }` which should be included in forward
pagination.
## Fix
Create a new util to use proper lexicographic order when sorting a
composite field.
---------
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>