Commit Graph
28 Commits
Author SHA1 Message Date
3290bf3ab1 fix(rest-api): prevent silent pagination failures and include valid options in enum validation errors (#20092)
# Summary 
(fixes #20044)

This PR implements two fixes for the REST API to enforce stricter
validation and provide better error messages.

Issue 1: Cursor parameter silently ignored
Problem: When users provided common cursor aliases (e.g., cursor, after,
before) instead of the correct parameter names (starting_after,
ending_before), the API silently ignored them and returned page 1 on
every request.
Solution: Added strict validation to detect common cursor aliases and
throw a clear error directing users to use the correct parameter names.
Files modified:
-
packages/twenty-server/src/engine/api/rest/input-request-parsers/rest-input-request-parser.exception.ts
-
packages/twenty-server/src/engine/api/rest/input-request-parsers/starting-after-parser-utils/parse-starting-after-rest-request.util.ts
-
packages/twenty-server/src/engine/api/rest/input-request-parsers/ending-before-parser-utils/parse-ending-before-rest-request.util.ts
- Test files for both parsers
Example error:
Invalid cursor parameter 'cursor'. Use 'starting_after' for pagination.
---
Issue 2: OpportunityStageEnum not validated on REST
Problem: When creating or updating opportunities via REST with an
invalid stage value, the API either silently dropped the value or
returned a generic error without listing valid options.
Solution: Updated the SELECT field validation to include valid options
in the error message.
Files modified:
-
packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-rating-and-select-field-or-throw.util.ts
- Test file
Example error:
Invalid value "BAD_VALUE" for field "stage". Valid values are: NEW,
SCREENING, MEETING, PROPOSAL, CUSTOMER
---
### Testing
- Added 5 new test cases for `parse-starting-after-rest-request.util.ts`
- Added 6 new test cases for `parse-ending-before-rest-request.util.ts`
- Added 1 new test case for
`validate-rating-and-select-field-or-throw.util.ts`
- All 21 tests passing
---
Breaking Changes
None - correct usage is unaffected.

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
2026-04-28 14:31:18 +00:00
EtienneandGitHub d562a384c2 Remove direct execution feature flag - WIP (#19254)
Bug fixes exposed by always-on direct execution
1. GraphQL spec compliance — data[field] = null on resolver error
direct-execution.service.ts — Changed from Promise.allSettled (which
lost the responseKey on rejection) to Promise.all with per-field
try/catch; errors now set data[responseKey] = null per spec
2. Empty object arguments skipped (extractArgumentsFromAst)
extract-arguments-from-ast.util.ts — Removed isEmptyObject check;
filter: {}, data: {} now correctly passed to resolvers instead of
silently dropped (which caused permissions to never be checked)
3. orderBy: {} factory default treated as "no ordering"
direct-execution.service.ts — Before calling the resolver, strips
orderBy: {} and orderByForRecords: {} (empty-object factory defaults
that mean "no ordering")
assert-find-many-args.util.ts / assert-group-by-args.util.ts — Accept {}
for orderBy without throwing
4. orderBy: { field: '...' } object auto-coerced to [{ field: '...' }]
array
direct-execution.service.ts — Applies GraphQL list coercion: a
non-array, non-empty orderBy object is wrapped in an array before
assertion and resolver call
5. totalCount and aggregate fields returned as strings from PostgreSQL
graphql-format-result-from-selected-fields.util.ts — Added
coerceAggregateValue that parses numeric strings to numbers for
totalCount, sum*, avg*, min*, max*, count*, percentageOf* fields
Test updates
nested-relation-queries.integration-spec.ts — Updated expected error
message from Yoga schema-validation message to direct execution resolver
message
~30 snapshot files — Updated to reflect direct execution's error
messages (different from Yoga schema-validation messages for input type
errors)
2026-04-03 15:23:01 +00:00
EtienneandGitHub 3d1c53ec9d Gql direct execution - Improvements (#18972)
#### Direct Execution  __typename & null backfill
##### __typename filling
The direct execution path now correctly derives __typename at every
level of the GraphQL response:
Connection types — CompanyConnection, CompanyEdge, Company, PageInfo
GroupBy types — TaskGroupByConnection (was incorrectly producing
TaskConnection)
Composite fields — Links, FullName, Currency, etc. handled by a
dedicated formatter (was inheriting the parent object's typename)
Previously, __typename was derived from the object's universal
identifier (a UUID), producing broken values like
20202020B3744779A56180086Cb2E17FConnection.
##### Null backfill
Selected fields missing from the resolver result are backfilled with
null, matching the standard Yoga schema behavior.
##### Integration test
A new test runs the same findMany query (with __typename at all
structural levels) through both paths — standard Yoga schema and direct
execution — and asserts identical output via toStrictEqual.
2026-03-30 17:20:25 +02:00
Charles BochetandGitHub 7b6fb52df7 fix: validate blocknote JSON in rich text fields (#18902)
## Summary
- **Backend**: Add JSON validation for the `blocknote` subfield in rich
text API inputs — rejects values that aren't valid JSON or aren't arrays
(BlockNote content is always `PartialBlock[]`). This prevents corrupted
data from being persisted to the database.
- **Frontend**: Replace all 5 unprotected `JSON.parse` calls on
blocknote content with the safe `parseJson` utility from
`twenty-shared`. Invalid content now degrades gracefully (empty block /
empty string / unchanged passthrough) instead of crashing the app.
- **Tests**: Added integration tests for invalid blocknote JSON (both
GraphQL and REST), unit tests for the new validation, and updated
existing test constants to use valid BlockNote JSON.

## Context
A user reported a `SyntaxError: Expected ',' or ']' after array element`
crash caused by malformed blocknote JSON stored in the database. The
data had `"children":[]` nested inside the `content` array instead of as
a sibling property. The API accepted this invalid JSON because it only
validated that `blocknote` was a string, not that it contained valid
JSON. On the frontend, 5 call sites used bare `JSON.parse` with no error
handling, causing a white-screen crash.

## Test plan
- [x] Unit tests pass: `validate-rich-text-field-or-throw.util.spec.ts`
(10/10)
- [x] Integration tests pass: `rich-text-field-create-input-validation`
(8/8)
- [ ] Verify creating a note with valid rich text still works end-to-end
- [ ] Verify API returns clear error when blocknote contains invalid
JSON
- [ ] Verify frontend renders empty block instead of crashing when
encountering corrupted data

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-24 14:53:15 +01:00
Charles BochetandGitHub d9eb317bb5 feat: rename RICH_TEXT_V2 → RICH_TEXT in codebase (keep DB value) (#18628)
## Summary

- Renames the `FieldMetadataType` enum key from `RICH_TEXT_V2` to
`RICH_TEXT` across the entire codebase, while keeping the underlying
string value as `'RICH_TEXT_V2'` to maintain PostgreSQL database
compatibility
- Renames all related types, guards, hooks, components, and files from
`*RichTextV2*` / `*rich-text-v2*` to `*RichText*` / `*rich-text*` (e.g.
`FormRichTextV2FieldInput` → `FormRichTextFieldInput`,
`isFieldRichTextV2` → `isFieldRichText`)
- Updates generated files (GraphQL schema, SDK types) to use the new key
while preserving the `RICH_TEXT_V2` string value for DB/API layer
- Updates i18n locale files, test snapshots, and integration tests to
reflect the rename

## Context

The legacy `RICH_TEXT` (V1) field type was deprecated and migrated to
`TEXT` in a previous PR (#18623). With V1 gone, the `RICH_TEXT_V2`
naming is no longer necessary — `RICH_TEXT` is now the canonical name.
The DB enum value stays `'RICH_TEXT_V2'` to avoid confusion with the
just-deprecated V1 type and to prevent a database migration.

## Test plan

- [x] `twenty-server` typecheck passes
- [x] `twenty-front` typecheck passes (only pre-existing Apollo client
errors remain)
- [x] `twenty-server` lint passes
- [x] `twenty-front` lint passes
- [x] `twenty-shared` build passes
- [ ] CI passes


Made with [Cursor](https://cursor.com)
2026-03-13 19:07:55 +01:00
Charles BochetandGitHub 46e515436e Deprecate legacy RICH_TEXT field metadata type (#18623)
## Summary

- Removes the deprecated `RICH_TEXT` (V1) field metadata type from the
codebase entirely
- Adds a 1.20 upgrade command that migrates existing `RICH_TEXT` fields
to `TEXT` in `core.fieldMetadata`
- Cleans up ~70 files across `twenty-shared`, `twenty-server`,
`twenty-front`, `twenty-sdk`, and `twenty-zapier`

## Context

`RICH_TEXT` was a legacy field type that stored rich text as a single
`text` column. It was already **read-only** — writes threw errors
directing users to `RICH_TEXT_V2` instead. `RICH_TEXT_V2` is the current
approach: a composite type with `blocknote` (editor JSON) and `markdown`
subfields. Keeping the deprecated type added maintenance burden without
any value.

Since the underlying database column type for `RICH_TEXT` was already
`text` (same as `TEXT`), the migration only needs to update the metadata
— no data migration or column changes required.

## Changes

### Upgrade command (new)
- `1-20-migrate-rich-text-to-text.command.ts` — runs `UPDATE
core."fieldMetadata" SET "type" = 'TEXT' WHERE "type" = 'RICH_TEXT'` per
workspace, with cache invalidation

### Enum & shared types
- Removed `RICH_TEXT` from `FieldMetadataType` enum
- Removed from `FieldMetadataDefaultValueMapping`,
`isFieldMetadataTextKind`

### Server (~30 files)
- Removed from type mapper (scalar, filter, order-by), data processors,
input transformer, filter operators, zod schemas, column type mapping,
searchable fields, RLS matching, OpenAPI schema, fake value generators
- Removed from field creation flow and field metadata type validator
- Updated dev seeder Pet `bio` field to `TEXT`
- Cleaned up mocks, snapshots, integration tests

### Frontend (~25 files)
- Deleted: `RichTextFieldDisplay`, `isFieldRichText`,
`isFieldRichTextValue`, `useRichTextFieldDisplay`
- Removed from `FieldDisplay`, `usePersistField`, `isFieldValueEmpty`,
`isRecordMatchingFilter`, `generateEmptyFieldValue`,
`isFieldCellSupported`, spreadsheet import, workflow fake values
- Removed from settings types, field type configs, and field creation
exclusion list
- Updated tests, mocks, and stories

### SDK & Zapier
- Removed from generated GraphQL schema and TypeScript types
- Removed from Zapier `computeInputFields`
2026-03-13 17:25:40 +01:00
martmullandGitHub 120096346a Add define post isntall logic function (#18248)
As title
2026-02-26 11:09:21 +01:00
EtienneGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
08a3d983cb Date & DateTime validation fixes / improvements (#18009)
Fixes https://github.com/twentyhq/twenty/issues/17138

- Backend should have strict date/dateTime format validation
- FE in import csv is more permissive

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-02-18 10:13:18 +00:00
16d414590b Lowercase email (#17775)
Fixes https://github.com/twentyhq/core-team-issues/issues/120 #16976
Partially related to #17711

Frontend check surprisingly was one-liner covering both email input and
import files

Migration script will be done in next commit

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
2026-02-10 18:24:49 +00:00
MarieandGitHub d4303469ff Improve qualification of rest errors (#17629)
Will help close
[sentry](https://twenty-v7.sentry.io/issues/6827612895/?environment=prod&environment=prod-eu&project=4507072499810304&query=is%3Aunresolved%20%21issue.type%3A%5Bperformance_consecutive_db_queries%2Cperformance_consecutive_http%2Cperformance_file_io_main_thread%2Cperformance_db_main_thread%2Cperformance_n_plus_one_db_queries%2Cperformance_n_plus_one_api_calls%2Cperformance_p95_endpoint_regression%2Cperformance_slow_db_query%2Cperformance_render_blocking_asset_span%2Cperformance_uncompressed_assets%2Cperformance_http_overhead%2Cperformance_large_http_payload%5D%20timesSeen%3A%3E10&referrer=issue-stream&sort=date):
a 400 error (attempt to filter on a `null` id) qualified as a 500 error
from rest api.

I don't know what was our long term plan on validation for rest api, I
suppose it's not a priority, making it acceptable to interceipt some
postgres errors based on their messages. Ideally we would have a
validation earlier, at args parsing level.

before
<img width="1286" height="460" alt="Capture d’écran 2026-02-02 à 14 08
53"
src="https://github.com/user-attachments/assets/bf3d34f9-1436-4739-8f8e-95b18f59045b"
/>

after
<img width="1222" height="438" alt="Capture d’écran 2026-02-02 à 14 09
01"
src="https://github.com/user-attachments/assets/e817eaff-1ab9-49fb-869d-ddfd00671fbf"
/>
2026-02-04 14:33:30 +00:00
EtienneandGitHub 4fcc424e24 Files field - add files field display and input + filtering (#17637)
This PR introduces a new FILES field type for Twenty CRM, allowing users
to attach multiple files to any record.

- Files field display
- Files field preview
- Files field input
- Files field filtering

To test : 
1/ need to activate feature flag `IS_FILES_FIELD_ENABLED` + create a new
FILES field

- display in read only, edit, inline, table
- edit
- filter
- export


closes https://github.com/twentyhq/core-team-issues/issues/2154


<img width="354" height="134" alt="Screenshot 2026-02-02 at 19 11 01"
src="https://github.com/user-attachments/assets/3c3de89e-f6b6-4526-b710-e4c7ee1a6d30"
/>
<img width="1081" height="933" alt="Screenshot 2026-02-02 at 19 10 41"
src="https://github.com/user-attachments/assets/7c9a7278-edb7-4d4a-882c-f7404689d011"
/>
<img width="1073" height="719" alt="Screenshot 2026-02-02 at 19 10 33"
src="https://github.com/user-attachments/assets/79cc372b-56a2-4cbf-b4fe-023adc4753a8"
/>
2026-02-04 10:55:48 +00:00
EtienneandGitHub 09de762285 Files v2 - FILES field update/create in common API (#17400)
## FILES Field update interface

```
mutation {
  updateCompany(
    id: "company-uuid"
    data: {
      filesfield: [
          { fileId: "new-file-uuid", label: "new-document.pdf" }
        ]
    }
  ) {
    id
    filesfield {
      fileId
      label
      extension
    }
  }
}
```
2026-01-29 13:33:26 +00:00
Lucas BordeauandGitHub 326585157c Fixed plain object in field value for workflow (#17470)
This PR fixes a bug that arises in `formatResult` following up the
recent refactor for DATE_TIME :
https://github.com/twentyhq/twenty/pull/17407

In the case of workflows, we pass a plain object to `formatResult` : 

```ts
{
  before: null, 
  after: '2026-01-27T10:59:15.525Z'
}
```

So a case has been added to handle this. 

@Weiko are we ok with this more restrictive else-if part in this util ?
We could also just put a `continue` for unknown shapes.
2026-01-27 13:21:56 +00:00
Lucas BordeauandGitHub a07590eba5 Change formatResult to return string instead of Date object for DATE_TIME (#17407)
This PR modifies our broadly used `formatResult` util to counter act
TypeORM transforming any date time to a `Date` object.

Instead we return the ISO string for any `DATE_TIME`, this way we're not
transporting Date object from one function to another in the backend.

We do this because there was problems working with events utils that
take string date time in parameters and received Date objects.

As this is a recurring problem and because it's an opinionated choice
from TypeORM, we chose to switch to string only in our codebase, from
TypeORM's output to frontend.
2026-01-23 18:22:01 +00:00
0091ef5f6c Sync built files (#17379)
as title, upload built files to local storage

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-23 13:43:53 +01:00
EtienneandGitHub 30c13fc947 Files v2 - Add new FILES field type (#17236)
In this PR : 
- New field type FieldMetadataType.FILES added (as jsonb in DB)
- Backend: GraphQL types, validation, REST API schema, data processor
handling
- Frontend: field configuration in settings
- Feature flag IS_FILES_FIELD_ENABLED to gate the feature
- Integration tests for create/filter validation
- Dev seed: Feature flag enabled + FILES field on survey result object


To do in next PRs : 
- Backend : 
-- new workspaceFile controller (for download) & new workspaceFile
upload resolver (for upload)
-- pre-hook/post-hook to ensure fileId existence + listener to ensure
cleaning
- Frontend : FILES field display/edit in table view, record, ...
2026-01-20 17:03:49 +00:00
Abdullah.andGitHub 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
59d3a14922 Common API - Add tests on position field validation at creation (#16630)
Co-authored-by: guillim <guigloo@msn.com>
2025-12-17 16:02:37 +00:00
GuillimandGitHub 5daef28328 Morph INPUT integration test (#16464)
- Adding a new target to the test setup suite
- We add the MORPH_RELATION to the list of types we wanna test in the
current test suites

Important:
I noticed the REST API was not working well with Morph relations. I
created [an
issue](https://github.com/twentyhq/core-team-issues/issues/2002) to work
on that. Within that timeframe, I `xdescribed` the related tests

Fixes https://github.com/twentyhq/core-team-issues/issues/1327
2025-12-11 10:10:30 +01:00
EtienneandGitHub 638d4015a1 Null equivalence - Activate FF for all (#16209) 2025-12-01 15:43:28 +01:00
EtienneandGitHub 2028a8f9be Null equivalence - Fix (#16050)
@charlesBochet 
In workflow codebase, NULL (instead of empty object) is expected on
workflow version object step field, when a new workflow is created for
example.
(packages/twenty-front/src/modules/workflow/workflow-diagram/utils/generateWorkflowDiagram.ts
- 42)
This case is not isolated and it creates many issues.

We decided to format NULL value to equivalent (empty string for text
field, empty object for raw_json) but it seems it complicates the dev x.

To unlock @Devessier I prefer revert the logic, the time we discuss how
to solve this cases.
2025-11-25 14:07:32 +01:00
EtienneandGitHub 208c0857ee common api - null equivalence (#15926)
closes https://github.com/twentyhq/core-team-issues/issues/1629

To do before requesting review : 
- filter update

Migration to come in an other PR


Strat : 
1/  Null transformation

- [x] Transform NULL equivalent value to NULL in field validation in
common api - pre-query - with feature flag
- [ ] Same logic in ORM (Not done, complex to handle feature flag here)
- [x] Transform NULL value to equivalent in data formatting in ORM -
post-query

2/ Migration (in other PR) for fieldMetadata not nullable with default
defaultValue (empty string, ...)

- [ ] Remove NOT NULL db constraint
- [ ] Update record value to NULL
- [ ] Update field metadata : isNullable:true
- [ ] Update uniqueIndex whereClause (also for standard uniqueIndex) 
- [ ] Activate feature flag

3/ Update metadata creation

- [x] No more default default value
- [x] Update standard field nullability
- [x] Remove index default whereClause for standard field

4/ Update filter

- [x] When filtering on NULL or empty string, be sure all records are
returned (the one with NULL + the one with "")

5/ Test

- [ ] Strat. to do
2025-11-24 18:57:47 +01:00
EtienneandGitHub 8998f3bd84 Fix int tests - update snapshots (#15944)
because of integration tests not working yesterday,
[PR](https://github.com/twentyhq/twenty/pull/15931) has been merged with
not updated snapshots
2025-11-20 10:05:49 +00:00
EtienneandGitHub 674ddbd525 Fix raw json validation (#15931)
Before validation in common layer, stringified json were accepted in raw
json field. Fix regression

related to
https://discord.com/channels/1130383047699738754/1130383048173682821/1440723288090218636
2025-11-19 19:05:02 +01:00
76cc07a5f7 Revert x2 - Common - Field validation (#15491) (#15879)
Revert https://github.com/twentyhq/twenty/pull/15821

Should not have been reverted. Conflicting with this
[PR](https://github.com/twentyhq/twenty/pull/15742),
[reverted](https://github.com/twentyhq/twenty/pull/15875)

Co-authored-by: Weiko <corentin@twenty.com>
2025-11-18 12:04:00 +01:00
martmullandGitHub 867422627c Revert "Common - Field validation (#15491)" (#15821)
This reverts commit 261cba40ef.
2025-11-14 13:47:22 +01:00
261cba40ef Common - Field validation (#15491)
Closes : https://github.com/twentyhq/core-team-issues/issues/1622

To do in other PR : 
- Add migration command for non nullable text, raw_json & array fields
- Add null transformation

---------

Co-authored-by: Weiko <corentin@twenty.com>
2025-11-13 15:45:35 +01:00
EtienneandGitHub 580ce312fd Common api - Add field create input validation integration testing (#15026)
closes https://github.com/twentyhq/core-team-issues/issues/1624
2025-10-20 18:19:50 +02:00