Commit Graph
708 Commits
Author SHA1 Message Date
Paul RastoinandGitHub d8f0115fef Improve view identification command perfs and reliability (#17161)
# Introduction
Instead of comparing existing to expected comparing expected to existing
Also improved logs and fallback use cases

# Test
Tested on a prod extract
2026-01-15 12:27:07 +00:00
Paul RastoinandGitHub 2c24180b44 Identify standard view fields and views (#17118)
# Introduction
Related https://github.com/twentyhq/core-team-issues/issues/1989

1/ Migration, applicationId and universalIdentifier are required on
entity ( save point migration + upgrade command fallback pattern )
2/ Backfill using previous `standardId` or `isCustom`

## Test
Both tested on prod extract
Some view field are set as non custom is prod whereas they should for
several manually handle-able workspace amount
2026-01-14 14:15:07 +00:00
Lucas BordeauandGitHub 6b14cfaa89 Fixes two critical bugs for DATE type (#17143)
This PR fixes two critical bugs with the DATE type, following up the
recent refactor around dates and time zones :
https://github.com/twentyhq/twenty/pull/16544

There are a lot of related bugs in Sentry, this PR should fix all bugs
that are of the form :

`Cannot parse: 2026-02-04T00:00:00.000Z`

# `node-postgres` date type

The package `node-postgres`, used by TypeORM, returns by default a Date
object for the date OID type.

But we can change this behavior without patching anything.

See the documentation for `pg-types` :
https://github.com/brianc/node-pg-types

Our fix is to call `setTypeParser` from `pg` to have the postgres "date"
type returned as a string always.

```ts
export const setPgDateTypeParser = () => {
  types.setTypeParser(PG_DATE_TYPE_OID, (val: string) => val);
};
```

Then in server's main.ts : 

```ts
const bootstrap = async () => {
  setPgDateTypeParser();
```

## Are we safe with this very low-level fix ?

Since TypeORM bypasses a string value returned by `pg` we are safe with
this modification at a very low-level.

```ts
else if (columnMetadata.type === "date") {
  value = DateUtils.mixedDateToDateString(value)
}
```


https://github.com/typeorm/typeorm/blob/0ec4079cd3760dc49247a02c54415f16a2a51766/src/driver/postgres/PostgresDriver.ts#L838

```ts
/**
* Converts given value into date string in a "YYYY-MM-DD" format.
*/
static mixedDateToDateString(value: string | Date): string {
  if (value instanceof Date) {
      return (
          this.formatZerolessValue(value.getFullYear(), 4) +
          "-" +
          this.formatZerolessValue(value.getMonth() + 1) +
          "-" +
          this.formatZerolessValue(value.getDate())
      )
  }

  return value
}
```


https://github.com/typeorm/typeorm/blob/6f3788b83730463e3b787b2a98bb41695e13caf8/src/util/DateUtils.ts#L28

For reference the original type parser seems to be configured in
node-pg-types, on the 1182 OID, which is an array of date / 1082 OID,
this type parser calls another small library `postgres-date` which
creates a JS Date. I couldn't find a type parser explicitly on 1082 in
the stack TypeORM -> node-postgres -> node-pg-types -> postgres-date

```ts
register(1182, parseStringArray) // date[]
``` 


https://github.com/brianc/node-pg-types/blob/26bfe645a8ddc0c73830b1b8c63f2c4f8265b24f/lib/textParsers.js#L168C19-L168C45

```ts
 static parse (dateString) {
  return new PGDateParser(dateString).getJSDate()
}
```


https://github.com/bendrucker/postgres-date/blob/b3060560ed62c250f7800d29e4b68a9d5a0622bd/index.js#L285


# Calendar view mixing DATE and DATE_TIME

At the time of the refactor, DATE type wasn't properly tested with
calendar view, thus the drag and drop of a card with a calendar view on
a DATE field and not a DATE_TIME field, was not working, this is now
fixed.
2026-01-14 13:38:24 +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
Paul RastoinandGitHub df108ea040 Identify standard objects (#17091)
# Introduction
Followup https://github.com/twentyhq/twenty/pull/16981

1/ Migration, applicationId and universalIdentifier are required on
entity ( save point migration + upgrade command fallback pattern )
2/ Backfill using previous standard ids
2026-01-12 18:06:13 +00:00
c795b8c52a RLS FE implementation (#17062)
## Summary
This PR introduces row-level security (RLS) permissions for roles in the
frontend, allowing fine-grained access control at the record level.
Users can now define permission rules that determine which specific
records a role can access based on dynamic conditions and filters.
## What's Changed
Implemented UI for configuring record-level permissions on object
permissions screens
Added support for defining permission predicates using filter conditions
(similar to advanced filters)
Introduced variable picker for dynamic permission rules (e.g., "me"
context for user-specific access)
Built predicate conversion layer to sync UI state with backend
permission structure
Extended GraphQL schema with mutations for upserting row-level
permission predicates
Fixed handling of orphaned RLS groups to prevent data inconsistencies
Added enterprise key validation for RLS features
The implementation enables scenarios like "users can only see their own
records" or "users can access records associated with their team."

<img width="687" height="702" alt="Screenshot 2026-01-09 at 23 07 02"
src="https://github.com/user-attachments/assets/33fe736e-6cbf-40bd-b2eb-c8a90c8d21bc"
/>

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-12 17:39:17 +00:00
Paul RastoinandGitHub a6f371a42a Identify standard field do deploy until IS_WORKSPACE_CREATION_V2_ENABLED is enabled in prod (#16981)
# Introduction

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

Do not merge until `IS_WORKSPACE_CREATION_V2_ENABLED` has been activated
by default, and so sync metadata has been deprecated by doing so. As the
sync metadata will attempt to insert `null` `applicationId` and
`universalIdentifier` values while creating a workspace

In this PR we're introducing a new `SyncableEntityRequired` which
enforces the non nullable `applicationId` and `universalIdentifier` on
extending entity

In this PR we also migrate the field metadata entity to extend the
required

## Identification upgrade command
This command will search for workspace field metadata entities that
aren't associated to an applicationId, dispatch them to either the
workspace-custom `applicationId` or the twenty-standard `applicationId`.
For the standard entities it will also set their universal identifier
based on the `STANDARD_OBJECTS` const hashmap

## Typeorm migration
As the non nullable `applicationId` and `universalIdentifier`migration
won't pass in the first we've been using the save point and upgrade
command migration fallback pattern

## Tests
Tested the command on a prod extract locally

Both `twenty-eng` and `twenty-for-twenty` have unexpected standard
objects
Please note that we will deprecate the `isCustom` and `standardId` col
later in the future

### Twenty-eng
```ts
[Nest] 98971  - 01/01/2026, 3:18:00 PM     LOG [IdentifyStandardEntitiesCommand] Successfully validated 600/600 field metadata update(s) for workspace 9870323e-22c3-4d14-9b7f-5bdc84f7d6ee (309 custom, 291 standard)
[Nest] 98971  - 01/01/2026, 3:18:00 PM    WARN [IdentifyStandardEntitiesCommand] Found 35 warning(s) while processing field metadata for workspace 9870323e-22c3-4d14-9b7f-5bdc84f7d6ee. These fields will become custom.
```

### Twenty for twenty

### Just created workspace
2026-01-12 09:59:01 +00:00
46e5420d20 dashboard workspace standard seeds (#16962)
# Introduction

In this pull request we're introducing new standard page layout, tabs
and widget ( 1 page layout, 1 tab and 8 widgets ) and also a new
opportunity field

Also now prefilling new records, 6 opportunities and a dashboard.

## Standard declaration
### New workspace creation
Relies on existing standard declaration builder

### Backfill command
We've been hacking through the standard builder in order to extract only
the standard page layout entities, updated their entity dependencies to
match the workspace ids so the validation passes


## Remark
- Refactored the `PageLayoutWidget` configuration type to be dynamically
typed through a generic discriminated union

---------

Co-authored-by: prastoin <paul@twenty.com>
2026-01-12 09:34:15 +00:00
d7b7e9def1 Cascade delete Task targets when tasks deleted - logic + migration command (#17019)
Co-authored-by: prastoin <paul@twenty.com>
2026-01-09 14:10:40 +00:00
Paul RastoinandGitHub 942d2fef83 Remove sync-metadata and IS_WORKSPACE_CREATION_V2_ENABLED feature flag (#16997)
# Introduction
Followup of
https://github.com/twentyhq/twenty/pull/17001#pullrequestreview-3638508738
close https://github.com/twentyhq/core-team-issues/issues/1910

We've completely decom the `sync-metadata` in production. We're now then
removing its implementation in favor of the v2.

## TODO:
- [x] Remove sync-metadata implem and commands
- [x] Remove workspace decorators 
- [x] Type each deprecated field to deprecated on their workspaceEntity
- [x] Remove the `workspace-sync-metadata` folder entirely
- [x] remove workspace migration
- [x] workspace migration removal migration
- [x] remove the `v2` references from workspace manager file names
- [x] remove the `v2` references from workspace manager modules
- [ ] Double check impact on translation file path updates


## Note
- Removed the gate logic
- Remains some service v2 naming, serverless needs to be migrated on v2
fully
- Removed workspaceMigration service app health consumption, making it
always returning up ( no more down ) cc @FelixMalfait ( quite obsolete
health check now, will require complete refactor once we introduce inter
app dependency etc )
2026-01-08 15:45:12 +00:00
Paul RastoinandGitHub 28e79de7b0 Fix workspace application fk command re-run (#17018)
# Introduction
The command is not idempotent, try to create an already existing FK
fails
- Always dropping the FK before recreating it in order to prevent this
- Removed the `remoteTable` and `remoteServer` from the command

We still have the `hasRunOnce` static var that will avoid re running it
if a workspace successfully passed the migration

Note: This is shared between both the upgrade command and the typeorm
migration

## Test
locally
```ts
atedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object person (20202020-e674-48e5-a542-72570eee7213) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object pet (custom) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object surveyResult (custom) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object rocket (custom) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] All objects already have updatedBy field for workspace 20202020-1c25-4d02-bf25-6aeccf7ea419
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [AddWorkspaceForeignKeysMigrationCommand] Successfully run AddWorkspaceForeignKeysMigrationCommand
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Upgrade for workspace 20202020-1c25-4d02-bf25-6aeccf7ea419 completed.
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Running command on workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db 2/2
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Upgrading workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db from=1.14.0 to=1.15.0 2/2
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [MigratePageLayoutWidgetConfigurationCommand] Starting migration of page layout widget configurations for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [MigratePageLayoutWidgetConfigurationCommand] Found 0 widget(s) needing migration out of 16 total
query: SELECT COUNT(1) AS "cnt" FROM "workspace_3ixj3i1a5avy16ptijtb3lae3"."note" "note" WHERE ( (("note"."position" = $1)) ) AND ( "note"."deletedAt" IS NULL ) -- PARAMETERS: ["NaN"]
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [FixNanPositionValuesInNotesCommand] Found 0 note(s) with NaN position values in workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [FixNanPositionValuesInNotesCommand] No NaN position values to fix
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Starting backfill of updatedBy field for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object note (20202020-0b00-45cd-b6f6-6cd806fc6804) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object task (20202020-1ba1-48ba-bc83-ef7e5990ed10) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object dashboard (20202020-3840-4b6d-9425-0c5188b05ca8) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object workflowRun (20202020-4e28-4e95-a9d7-6c00874f843c) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object workflow (20202020-62be-406c-b9ca-8caa50d51392) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object opportunity (20202020-9549-49dd-b2b2-883999db8938) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object company (20202020-b374-4779-a561-80086cb2e17f) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object attachment (20202020-bd3d-4c60-8dca-571c71d4447a) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object person (20202020-e674-48e5-a542-72570eee7213) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object surveyResult (custom) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] All objects already have updatedBy field for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [AddWorkspaceForeignKeysMigrationCommand] Skipping has already been run once AddWorkspaceForeignKeysMigrationCommand
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Upgrade for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db completed.
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Command completed!
```
2026-01-08 14:12:57 +00:00
WeikoandGitHub 66b2882ac4 BREAKING CHANGE: Removing remote integration feature (#17001)
## Context
The feature has not been maintained for more than a year and was never
officially launched.
This PR removes its code due to the upcoming refactoring of the
sync-metadata that will break its logic if not handled properly and it
would be too costly for the time being.

TODO:
- remove isRemote from object/field metadata
2026-01-08 09:14:51 +00:00
Paul RastoinandGitHub 96f7f1cb0e Fix 1-15 upgrade commands bundle (#16957) 2026-01-06 14:13:40 +00:00
Paul RastoinandGitHub bd9e5986d2 Clean orphan metadata (#16914)
# Introduction
Followup https://github.com/twentyhq/twenty/pull/16863

Important note: This is not an upgrade command and will have to be
manually run

In this pull request we're introducing a coding that will allow this
[migration](https://github.com/twentyhq/twenty/blob/clean-orphan-metadata/packages/twenty-server/src/database/typeorm/core/migrations/utils/1767002571103-addWorkspaceForeignKeys.util.ts#L3)
to pass, it enforces the `workspaceId` foreignKey on all metadata
entities. Allowing workspace deletion cascading of all its related
entities and avoiding orphan metadata entities to reoccur in the future

Also introduced a small migration that will set the workspaceId col type
to `uuid`, as it has been historically `varchar`
This migration is a requirement for the above command to work
successfully


## Note
Chunking by relations fields the orphan field deletion as would take way
too much time within a transac,

## Test
Tested on a prod extract locally ( both dry and not dry )
2026-01-06 13:36:53 +01:00
Félix MalfaitandGitHub 0173e40a20 feat: Serverless Functions as AI Tools (#16919)
## Summary

This PR enables serverless functions to be exposed as AI tools, allowing
them to be used by AI agents.

### Changes

- Added new `SERVERLESS_FUNCTION` tool category
- Added `toolDescription`, `toolInputSchema`, and `toolOutputSchema`
fields to serverless functions
- Created database migration for the new schema columns
- Added tool index query and resolver for fetching available tools
- Added Settings AI page tabs (Skills, Tools, Settings) with new tools
table
- Added utility to convert tool schema to JSON schema format
- Updated frontend to display tools in the settings page

### Implementation Details

- Serverless functions can now define tool metadata (description,
input/output schemas)
- These functions are automatically registered in the tool registry
- The tool index endpoint allows querying available tools with their
schemas
- Settings page now has a dedicated Tools tab showing all available
tools
2026-01-05 11:13:06 +01:00
Félix MalfaitandGitHub 21ff42074d feat: implement skills system for AI agents (#16865)
## Summary
This PR introduces a Skills system for AI agents, inspired by the [Agent
Skills specification](https://agentskills.io/specification).

## Changes

### Backend
- **SkillEntity**: New database entity with migration for storing skills
- **V2 Sync Mechanism**: Implemented FlatSkill, builders, validators,
and action handlers following the v2 flat entity pattern
- **Standard Skills**: Pre-defined skills (workflow-building,
data-manipulation, dashboard-building, metadata-building, research,
code-interpreter, xlsx, pdf, docx, pptx)
- **GraphQL API**: CRUD operations for skills with proper guards and
permissions
- **Workspace Cache**: Integrated skills into the workspace cache system

### Frontend  
- **Skills Table**: Searchable table in AI settings showing all skills
- **Skill Form**: Create/edit page with Label (primary), Description,
and Content (markdown editor)
- **API Name**: Following existing patterns, name is derived from label
with advanced settings toggle for custom API names
- **Standard vs Custom**: Standard skills are read-only, custom skills
can be edited/deleted

## Key Design Decisions
- Skills are stored in the database (Salesforce-like approach) rather
than files
- Name is derived from Label by default (isLabelSyncedWithName pattern)
- Skills reference functions/files via @ mentions in markdown content
rather than explicit relations
- Standard skills are synced from code, custom skills are created via UI

## Screenshots
Skills table and form UI follow existing settings patterns.

## Testing
- [x] Lint passes
- [x] Typecheck passes
- [ ] CI tests
2026-01-02 14:22:01 +00:00
Paul RastoinandGitHub 98a9ae2a0e Migrate view filter group to v2 (#16876)
## Introduction
On the side hanlded PR with a // agents on another repo
Made several iterations to fix behavior and direction
Find below auto-generated PR description

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

Created generic tooling for entity circular dep checking, will be useful
for permissions validation too @Weiko


## Migrate `viewFilterGroup` entity to v2 flat architecture

### Summary
Migrates the `viewFilterGroup` entity from v1 to the v2 flat entity
architecture, following the established patterns for other v2 entities
like `viewFilter`, `view`, and `viewField`.

### Changes

**Types & Constants**
- Added `FlatViewFilterGroup` and `FlatViewFilterGroupMaps` types
- Added editable properties constant for `viewFilterGroup`
- Registered `viewFilterGroup` in `ALL_METADATA_NAME`,
`ALL_METADATA_RELATION_PROPERTIES`,
`ALL_METADATA_MANY_TO_ONE_RELATIONS`, and related constants

**Cache Service**
- Created `WorkspaceFlatViewFilterGroupMapCacheService` with proper
relation loading for `viewFilters` and `childViewFilterGroups`
- Updated `WorkspaceFlatViewMapCacheService` to load `viewFilterGroups`
relation

**Builder & Validator**
- Created `WorkspaceMigrationV2ViewFilterGroupActionsBuilderService`
- Created `FlatViewFilterGroupValidatorService` with creation, update,
and deletion validation
- Integrated validation into the orchestrator service (runs before
`viewFilter` validation)

**Action Handlers**
- Created create, update, and delete action handlers for
`viewFilterGroup`

**Service Migration**
- Rewrote `ViewFilterGroupService` to use v2 migration pattern with
`WorkspaceMigrationValidateBuildAndRunService`
- Created utility functions for transforming DTOs to flat entities

**Database Migration**
- Added migration to make `parentViewFilterGroupId` foreign key
deferrable (handles self-referential parent/child insertions)

**ViewFilter Integration**
- Added `viewFilterGroupId` validation in
`FlatViewFilterValidatorService`
- Updated `viewFilter` many-to-one relations to include
`viewFilterGroup`

**Tests**
- Added integration tests for successful creation, update, deletion, and
destruction
- Added failing test cases for non-existent entities and invalid
references
- Added failing test for `viewFilter` creation with non-existent
`viewFilterGroupId`

### Breaking Changes
None - existing API contracts are preserved.
2026-01-02 14:16:01 +01:00
15b21570ae Row level permissions - POC 1 (#16599)
## Context
This PR adds the core structure for RLS implementation:
- RLS data model
- RLS service layer
- RLS WorkspaceMigration and Syncable Entity + cache + Validations
- RLS resolver layer
- ORM layer with RLS Predicate to ORM WHERE clause conversion with
workspaceMember record transposition

Tests are missing though

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Establishes core row-level permissions infrastructure and enforcement
across the stack.
> 
> - Backend: new `rowLevelPermissionPredicate` and
`rowLevelPermissionPredicateGroup` entities, TypeORM migration, feature
flag `IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED`, flat-entity
maps/cache wiring, services and GraphQL resolvers for CRUD, and
inclusion of `workspaceMember` in auth context
> - ORM: applies row-level permission predicates to SELECT, DELETE, and
SOFT DELETE query builders; propagates context through
GlobalWorkspaceOrmManager/EntityManager
> - GraphQL: generated schema/types/queries/mutations for
creating/updating/deleting/fetching predicates and groups
> - Frontend: settings page adds a gated "Record-level" section
(placeholder) and metadata error handler labels for new entities
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fe955cc458. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2025-12-31 16:15:17 +01:00
Paul RastoinandGitHub eeb91d9a96 [DO_NOT_RELEASE_MAIN_UNTIL_MERGED] Prevent migration failure due to workspace orphan metadata rows (#16863)
# Introduction
The `AddWorkspaceForeignKeys1767002571103` migration would fail when
released in production right now, as `foreignKey` be applicable as
there's a lof of orphan entries in database

As a workaround in order not to block any patch release we're
fallbacking the migration using save point and an upgrade command that
will attempt to apply the `foreignKey` on every workspace upgrade until
it succeed

We should keep in mind that any new fresh self installation will have
the foreignKey double checked that it would not implies regression on
workspace deletion using the integration tests

## Cleaning upgrade command
We won't implement the cleaning command in this PR yet either will I as
discussed with @Weiko someone else might be taking the subject starting
next week

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Strengthens workspace data integrity and makes the FK migration
resilient.
> 
> - Adds `upgrade:1-16:add-workspace-foreign-keys-migration` command to
apply `workspaceId` FKs once per run; wires into
`V1_16_UpgradeVersionCommandModule` and 1.16 upgrade sequence
> - Refactors migration `1767002571103` to use
`addWorkspaceForeignKeysQueries` util and wrap in a savepoint,
swallowing errors to avoid blocking releases
> - Extracts FK DDL into
`utils/1767002571103-addWorkspaceForeignKeys.util` for reuse by command
and migration
> - Removes duplicate `workspaceId` columns from entities (e.g.,
`cronTrigger`, `databaseEventTrigger`, `indexMetadata`,
`objectMetadata`, `roleTarget`, `role`, `serverlessFunction`) relying on
`SyncableEntity`; keeps indexes/relations
> - Marks legacy delete paths as deprecated; temporarily extends
`WorkspaceManagerService.delete` to also delete `serverlessFunction` by
`workspaceId`
> - Updates wiring to inject `ServerlessFunctionEntity` repository in
`workspace-manager` module/service and corresponding unit test
> - Extends integration tests and adds GraphQL helpers to create
serverless functions and triggers; verifies cascade deletion of related
metadata on workspace removal
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6805bf5d1b32828b4bb1e9f130bfe6e478f66aee. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
2025-12-31 11:52:21 +00:00
Paul RastoinandGitHub e3ffdb0c2b [BREAKING_CHANGE_NESTED_WORKSPACE]Refactor FlatEntity typing in aim of introducing UniversalFlatEntity (#16701)
# Introduction
Added a `WorkspaceRelated` and `AllNonWorkspaceRelatedEntity` to
simplify the `FlatEntityFrom` that now do not expect a string literal to
omit and itself builds the related many to one entities foreign key
aggregators

We now have the type grain over relation to syncable or just workspace
related entities

Added a migrations that sets the fk on missing entities

## Next
In upcoming PR we will be able to introduce such below type
```ts
import { type CastRecordTypeOrmDatePropertiesToString } from 'src/engine/metadata-modules/flat-entity/types/cast-record-typeorm-date-properties-to-string.type';
import { type ExtractEntityManyToOneEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/types/extract-entity-many-to-one-entity-relation-properties.type';
import { type ExtractEntityOneToManyEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/types/extract-entity-one-to-many-entity-relation-properties.type';
import { type ExtractEntityRelatedEntityProperties } from 'src/engine/metadata-modules/flat-entity/types/extract-entity-related-entity-properties.type';
import { type RemoveSuffix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/remove-suffix.type';
import { type SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/types/syncable-entity.interface';

export type UniversalFlatEntityFrom<TEntity extends SyncableEntity> = Omit<
  TEntity,
  | `${ExtractEntityManyToOneEntityRelationProperties<TEntity> & string}Id`
  | ExtractEntityRelatedEntityProperties<TEntity>
  | 'application'
  | 'workspaceId'
  | 'applicationId'
  | keyof CastRecordTypeOrmDatePropertiesToString<TEntity>
> &
  CastRecordTypeOrmDatePropertiesToString<TEntity> & {
    [P in ExtractEntityManyToOneEntityRelationProperties<TEntity> &
      string as `${RemoveSuffix<P, 's'>}UniversalIdentifier`]: string;
  } & {
    [P in ExtractEntityOneToManyEntityRelationProperties<
      TEntity,
      SyncableEntity
    > &
      string as `${RemoveSuffix<P, 's'>}UniversalIdentifiers`]: string[];
  };

```
2025-12-30 13:47:02 +00:00
720348c583 Add upgrade commands to backfill updatedBy field and view fields (#16845)
---
prastoin edit
## Introduction
As we're deprecating the sync metadata we cannot rely on it anymore in
order to create the new standard updatedBy field
In this PR we introduce a command that will backfill the dynamic field
on both workspace standard and custom objects, for standard object it
will create a standard fields ( twenty-standard app scoped ) and for
custom one it will create a custom field ( worksapce-custom-app scoped )

## Testing method
Checkout `1.14.0` `yarn` and `npx nx database:reset twenty-server`
checkout PR and `yarn` `npx nx build twenty-server` and `yarn
database:migrate:prod` finally running the command

#### Before
<img width="2244" height="1464" alt="image"
src="https://github.com/user-attachments/assets/2fb866cd-13b8-4152-99b8-1fcc813b1d46"
/>

#### After
<img width="2244" height="1464" alt="image"
src="https://github.com/user-attachments/assets/b836ac06-c7b8-4add-bee1-bc1963418f29"
/>


#### Logs
```ts
[Nest] 20678  - 12/30/2025, 1:47:35 PM     LOG [BackfillUpdatedByFieldCommand] Found 12 objects that need updatedBy field
[EntityBuilder fieldMetadata] matrix computation: 3.994ms
[EntityBuilder fieldMetadata] creation validation: 1.822ms
[EntityBuilder fieldMetadata] deletion validation: 0.016ms
[EntityBuilder fieldMetadata] update validation: 0.009ms
[EntityBuilder fieldMetadata] entity processing: 6.098ms
[EntityBuilder fieldMetadata] validateAndBuild: 10.217ms
[EntityBuilder index] matrix computation: 0.857ms
[EntityBuilder index] creation validation: 0.003ms
[EntityBuilder index] deletion validation: 0.017ms
[EntityBuilder index] update validation: 0.008ms
[EntityBuilder index] entity processing: 4.721ms
[EntityBuilder index] validateAndBuild: 5.632ms
[Runner] Initial cache retrieval: 0.07ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 7.69ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 10.531ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 5.354ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 6.134ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 2.507ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 3.745ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 1.113ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 1.585ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 1.223ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.221ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 5.375ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 5.943ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 1.363ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 1.997ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 2.03ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.982ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 0.88ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.977ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 9.638ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 11.297ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 1.581ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.248ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 0.847ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 1.732ms
[Runner] Transaction execution: 82.555ms
[Runner] Cache invalidation flatFieldMetadataMaps,flatIndexMaps,flatObjectMetadataMaps: 89.247ms
[Runner] Total execution: 171.963ms
[Nest] 20678  - 12/30/2025, 1:47:35 PM     LOG [BackfillUpdatedByFieldCommand] Successfully backfilled updatedBy field for 12 objects in workspace 20202020-1c25-4d02-bf25-6aeccf7ea419
[Nest] 20678  - 12/30/2025, 1:47:35 PM     LOG [BackfillUpdatedByFieldCommand] Running command on workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db 2/2
[Nest] 20678  - 12/30/2025, 1:47:35 PM     LOG [BackfillUpdatedByFieldCommand] Starting backfill of updatedBy field for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db
[Nest] 20678  - 12/30/2025, 1:47:35 PM     LOG [BackfillUpdatedByFieldCommand] Found 10 objects that need updatedBy field
[EntityBuilder fieldMetadata] matrix computation: 3.224ms
[EntityBuilder fieldMetadata] creation validation: 0.969ms
[EntityBuilder fieldMetadata] deletion validation: 0.014ms
[EntityBuilder fieldMetadata] update validation: 0.002ms
[EntityBuilder fieldMetadata] entity processing: 5.149ms
[EntityBuilder fieldMetadata] validateAndBuild: 8.472ms
[EntityBuilder index] matrix computation: 0.785ms
[EntityBuilder index] creation validation: 0.002ms
[EntityBuilder index] deletion validation: 0.014ms
[EntityBuilder index] update validation: 0.002ms
[EntityBuilder index] entity processing: 3.818ms
[EntityBuilder index] validateAndBuild: 4.637ms
[Runner] Initial cache retrieval: 0.05ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 2.964ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 3.902ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 1.502ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.039ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 2.673ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 3.403ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 1.143ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.123ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 2.033ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.954ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 1.826ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.903ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 1.495ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.106ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 14.014ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 14.373ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 1.669ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 2.48ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForMetadata: 0.62ms
[BaseWorkspaceMigrationRunnerActionHandlerService] create_field executeForWorkspaceSchema: 1.048ms
[Runner] Transaction execution: 73.222ms
[Runner] Cache invalidation flatFieldMetadataMaps,flatIndexMaps,flatObjectMetadataMaps: 37.703ms
[Runner] Total execution: 111.071ms
```
---

---------

Co-authored-by: prastoin <paul@twenty.com>
2025-12-30 14:05:26 +01:00
4135a6473a [BREAKING_CHANGE_DASHBOARDS][DASHBOARD_CACHE_FLUSH_REQUIRED] Refactor page layout widget configuration type (#16671)
# Introduction
In this pull-request we're refactoring the page layout widget
configuration entity to be containing its discriminated key simplifying
underlying code and maintainability
- Made the configuration and title non nullable
- Introduced a generic predicate for the `widgetConfigurationType`
- Upgraded command to remove `graphType` and insert new
`configurationType` to existing entries
- Migrated frontend to new type system

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com>
2025-12-29 15:46:59 +01:00
MarieandGitHub bb18f78f1b [Fix] Fix NaN position in notes resulting in not being able to create notes (#16818)
Following [discord
thread](https://discord.com/channels/1130383047699738754/1453910755387899996/1453910755387899996),
reproductible on twenty-eng


https://github.com/user-attachments/assets/ae7f363d-87e1-44fa-8fe2-ee78412d62a7

Records positions are computed at record creation, depending on the
position arg from the request, being equal to `last`, `first`, or not
present.
When being equal to last, as it is done when creating a note from the
product, the position is calculated using `.maximum()` function which
uses postgres' MAX function. If there is a `NaN` value among the list,
the MAX will return `NaN` too. So if for some reason there is a NaN
somewhere in the position column, all subsequent records being created
with last position argument will be created with NaN value. Until [this
PR](https://github.com/twentyhq/twenty/pull/16630), where we introduced
a validation on position at record creation which throws when NaN is
trying to be introduced as a position, this was going silent. (fyi
@etiennejouan , not on you at all but for info)

Looking into twenty-eng workspace, I found note records with NaN
position dating back to august 2025, making it hard to understand and
debug why they were introduced with NaN position. So I did not find the
real root cause, but I suggest to
- update record-position.service to fix the issue for subsequent records
that go through this service (which is what is currently broken)
- run a command to fix the existing records with NaN position for Notes,
as it is where the issue happened for both the user reporting the issue
on discord, and us on twenty-eng. So hopefully the problem was limited
to Notes
2025-12-29 13:55:20 +01:00
martmullandGitHub bb73cbc380 1774 extensibility v1 create an exhaustive documentation readme or dedicated section in twenty contributing doc (#16751)
As title

<img width="1108" height="894" alt="image"
src="https://github.com/user-attachments/assets/e2dc7e12-72e3-4ca3-ac7b-a94de547f82a"
/>
2025-12-22 15:19:11 +01:00
Paul RastoinandGitHub 8acfa60412 Fix standard agent and roles deletion command (#16686)
# Introduction
Caught red handed, introduced a failing command in
https://github.com/twentyhq/twenty/pull/16499 that was failing even in
system build which is should not
2025-12-18 19:14:24 +01:00
Baptiste DevessierandGitHub b5ebc44fee Add field widget (#16609)
- Ability to display the details of a field
- The field can be edited (relations edition will be supported later)
- For now, the widget configuration stores the name of the field instead
of its fieldMetadataId. A hook resolves the fieldMetadataId from the
list of fields and the provided name. This will be replaced once we
migrate the configuration to the backend.

## Demo


https://github.com/user-attachments/assets/ab7efbda-66b2-46c1-b641-c350977c31dd

## Remaining to do

- Edition of relations
2025-12-18 17:25:51 +00:00
Paul RastoinandGitHub 47a8a15598 Metadata modules for PageLayoutTab PageLayoutWidget (#16662)
# Introduction
Creating dedicated folders and module for both `page-layout-tab` and
`page-layout-widget`

The addition diff with deletion is due to the module being added
2025-12-18 11:15:29 +00:00
Paul RastoinandGitHub 0e6a8c04c4 Async validators and additional cache maps in v2 Builder (#16618)
# Introduction
@bosiraphael has to introduce async validators and feature flag
contextual validator
In this way in this PR we make all entity validators asyncable
Also added an `additionalCacheDataMaps` to the low level args validators
2025-12-17 15:43:25 +01:00
martmullandGitHub 3ac72683da Update migration command (#16578)
Avoid pg_ table request
2025-12-16 13:35:03 +00:00
Paul RastoinandGitHub 75bba5a8ee Standard Agent, Role, Role target (#16499)
# Introduction
In this pullrequest have been migrated to the flat standard entities:
Role, Agent and RoleTargets.

## What happens
- Removed createStandardMorph tool util in favor of dynamic typing of
`createMorphOrRelationStandardField`
- Implemented a command to remove standard agents and their role that
has been removed in https://github.com/twentyhq/twenty/pull/16513 also
added a default role target to data manipulator role to the only
remaining agent
- Implemented an agent deleteMany service handler
2025-12-16 14:17:31 +01:00
MarieandGitHub a0b963ef86 Remove viewGroup.fieldMetadataId (#16571)
Final step of
https://github.com/orgs/twentyhq/projects/1/views/8?pane=issue&itemId=142348748&issue=twentyhq%7Ccore-team-issues%7C1965

Removing viewGroup.fieldMetadataId.
It's already not used in FE anymore
2025-12-15 17:58:45 +01:00
martmullandGitHub e289f3056e 1895 extensibility v1 application tokens 3 (#16504)
- moves applicationRoleId to application entity
- add new `APPLICATION` FieldActorSource and `APPLICATION`
JwtTokenTypeEnum value
- create a new token with applicationId when executing a function
- when applicationId is in token, check for application.defaultRole
permissions
-use twenty-shared types in `twenty-sdk/application`
- create a new import from generate called "Twenty" that you can use
directly without having to set TWENTY_API_KEY AND TWENTY_API_URL (keep
metadata or core parameter only)
- provide to serverless unique one time BEARER TOKEN to run it

Result
<img width="977" height="566" alt="image"
src="https://github.com/user-attachments/assets/e78428a0-5b13-4975-aa13-58ee3b32450c"
/>

<img width="910" height="596" alt="image"
src="https://github.com/user-attachments/assets/6ec72bf5-7655-4093-a45e-ad269595a324"
/>

<img width="741" height="568" alt="image"
src="https://github.com/user-attachments/assets/7683944c-fd79-4417-8fb2-8e4815cc112f"
/>
2025-12-15 17:44:23 +01:00
EtienneandGitHub 3e55e772d4 Update null command (#16567)
Remove version condition to re-run the command on upgraded workspaces on
which it fails
2025-12-15 13:55:32 +00:00
Paul RastoinandGitHub 8c79353bfb Fix rename index collides with existing v2 index (#16560)
## Introduction
When migrating a v1 index name to v2 it might collide with an existing
v2 index
In this case we remove both the v1 metadata and pg index

In case of a metadata and pg_index desync this might occur too late in
the process that's why we have two fallback
One computing the v1 deletion from the metadata and another one in the
catch block of the v1 to migration transaction commit
2025-12-15 11:06:09 +01:00
Paul RastoinandGitHub d189e3f57e Fix rename command error code edge case (#16556) 2025-12-15 08:36:35 +00:00
Paul RastoinandGitHub f0af947331 [RenameIndexCommand] Fix orphaned index edge case (#16539)
We've been facing orphaned metadata index that would result in alter
error, now if we encounter one we just delete it
2025-12-12 16:44:00 +00:00
Paul RastoinandGitHub 59663ec34e fix(server): non blocking CleanEmptyStringNullInTextFieldsCommand error (#16529)
# Introduction
Getting query timeout on prod upgrade for workspace that has huge
timeline activity table
2025-12-12 16:02:23 +01:00
Félix MalfaitandGitHub 4f91b48470 feat(ai): add context usage display to AI chat (BREAKING: deploy server first) (#16518)
## Summary

- Add a context usage indicator to the AI chat interface inspired by
Vercel's AI SDK Context component
- Display token consumption, context window utilization percentage, and
estimated cost in credits
- Show a circular progress ring with percentage, revealing detailed
breakdown on hover

## Changes

### Backend
- Stream usage metadata (tokens, model config) via `messageMetadata`
callback in `agent-chat-streaming.service.ts`
- Return model config from `chat-execution.service.ts`
- Add usage and model types to `ExtendedUIMessage` metadata

### Frontend
- New `ContextUsageProgressRing` component - circular SVG progress
indicator
- New `AIChatContextUsageButton` component with hover card showing:
  - Progress bar with used/total tokens
  - Input/output token counts with credit costs
  - Total credits consumed
- Track cumulative usage in Recoil state (`agentChatUsageState`)
- Reset usage when creating new chat thread
- Integrate button into `AIChatTab`

## Test plan

- [ ] Open AI chat and send a message
- [ ] Verify the context usage button appears with percentage
- [ ] Hover over the button to see detailed breakdown
- [ ] Verify credits are calculated correctly
- [ ] Create a new chat thread and verify usage resets to 0
2025-12-12 13:42:00 +01:00
WeikoandGitHub 083a038f8a Deprecate workspace datasoure (#16507) 2025-12-11 18:27:49 +01:00
Paul RastoinandGitHub f06a5ccacd Remove sync metadata from upgrade (#16491)
# Introduction
Related https://github.com/twentyhq/core-team-issues/issues/1910
From now on the upgrade won't integrate any sync metadata as it's going
to be deprecated very soon
Any updates to about to removes workspace-entity or standard flat entity
will require a dedicated upgrade command, what we've already started
doing during the 1.13 sprint, until we have totally migrated the v2 to
be workspace agnostic
2025-12-11 14:50:56 +01:00
GuillimandGitHub b83dc3aaff TimelineActivity migration to morph (#15652)
# TimelineActivity migration to morph


- Creates `timelineActivities2` relations on Company, Dashboard, Note,
Opportunity, Person, Task, Workflow, WorkflowRun, and WorkflowVersion
entities with proper metadata and cascade delete behavior.

It was required to create standard fields as well since the
mapObjectMetadataByUniqueIdentifier needs it. otherwise the fields won't
be considered

- Feature Flag `IS_TIMELINE_ACTIVITY_MIGRATED` necessary to have the two
states in parallel. It is used as a stamp once the migration has been
run

- Migration is done using the coreDataSource. Why ?
even though is unsafe to use, the first implementation of the migration
took forever on each workspace. See [this
commit](https://github.com/twentyhq/twenty/pull/15652/commits/477011e8d7d4c580f79ba7ec4a8fb002a3ec86b2)

The plan for this complex migration is as follows :

![plan](https://github.com/user-attachments/assets/51c63ea6-fb0d-40b4-b99d-3e0b35a204e6)
Note: we will need to rename fields in the release 1.12 (there is no
easy way to do all this in one release)
2025-12-11 14:28:26 +01:00
WeikoandGitHub 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
Abdul RahmanandGitHub 1839f8e946 Fix: Persist hide empty groups setting on backend (BREAKING: deploy server first) (#16385)
Closes #13754 and [core team issue
#414](https://github.com/twentyhq/core-team-issues/issues/414)
2025-12-10 19:10:29 +05:30
Paul RastoinandGitHub 20879c8147 Standard views tooling (#16436)
# Introduction
In this PR we've introduced the type safe generation tooling for
standard view, view fields, view filters and view groups.
Also generated the ids before such as what was done for object and
fields, it's still temporary as will be replaced by universalIdentifier
mapping afterwards

## Task views
In this PR only implemented the `task` views and view groups, filters
and fields in order to battle test all the generation tools
Will create a dedicated PR that will implement all the remaining views.
2025-12-10 14:29:01 +01:00
Paul RastoinandGitHub 7b98804ec1 Fix flat field metadata date type (#16445)
# Introduction
Following https://github.com/twentyhq/twenty/pull/16420
2025-12-09 19:53:36 +01:00
Paul RastoinandGitHub e8d4f11d8e Standard index as code introduction + type refactor (#16426)
# Introduction
Related https://github.com/twentyhq/core-team-issues/issues/1995

In this PR we're introducing the standard index tools for their
declaration
Also adding a common typing in order to have a simily consistency across
standard builders

Will implement remaining standard index builder in an other PR
2025-12-09 14:52:25 +01:00
Paul RastoinandGitHub 4996f3dd28 Finalize twenty standard app as workspace migration object and fields (#16353)
# Introduction
Related to https://github.com/twentyhq/core-team-issues/issues/1995
In this PR we're fixing the remaining object/fields validation errors
resulting from standard objects and fields now passing a validation that
wasn't when using the sync metadata

## Key Changes
- **Field naming**: Renamed `iCalUID` to `iCalUid` for consistent
camelCase convention across calendar events
- **Enum standardization**: Uppercased enum values for message channels
(email→EMAIL), message participants (from→FROM, to→TO, cc→CC, bcc→BCC),
and message direction (incoming→INCOMING, outgoing→OUTGOING)
- **Label simplification**: Removed example values from workspace member
number format labels for cleaner UI
- **Migration infrastructure**: Added `isSystemBuild` flag throughout
field metadata service pipeline to allow system-level updates of
standard fields that bypass normal restrictions

## Migrating the existing data
We've created an upgrade command that will identify using the existing
object and field standard id field that needs to be updated, even though
the sync metadata still in usage could have fix them ( and the goal is
to deprecate it by the end of the sprint )
We will call the updateOneField for each of them, we're passing by the
field service in order to battle test what are going to be the temporary
way to handle standard migrations when we will start deprecating the
sync metadata but haven't still refactored the v2 workspace migration to
be workspace agnostic

## Twenty eng migration
Tested the whole migration + upgrade on twenty eng
Here are generated workspace migration
Records are handled natively gracefully too

### ICalUid
```json
{
  "status": "success",
  "workspaceMigration": {
    "relatedFlatEntityMapsKeys": [
      "flatFieldMetadataMaps",
      "flatIndexMaps",
      "flatViewFilterMaps",
      "flatViewGroupMaps",
      "flatViewMaps",
      "flatViewFieldMaps",
      "flatObjectMetadataMaps"
    ],
    "actions": [
      {
        "type": "update_field",
        "fieldMetadataId": "",
        "objectMetadataId": "",
        "updates": [
          {
            "from": "iCalUID",
            "to": "iCalUid",
            "property": "name"
          }
        ]
      }
    ],
    "workspaceId": ""
  }
}
```

### Incoming Outgoing
None as already caps in database somehow
```json
{
  "status": "success",
  "workspaceMigration": {
    "relatedFlatEntityMapsKeys": [
      "flatFieldMetadataMaps",
      "flatIndexMaps",
      "flatViewFilterMaps",
      "flatViewGroupMaps",
      "flatViewMaps",
      "flatViewFieldMaps",
      "flatObjectMetadataMaps"
    ],
    "actions": [],
    "workspaceId": ""
  }
}
```

### EMAIL
```json
{
  "status": "success",
  "workspaceMigration": {
    "relatedFlatEntityMapsKeys": [
      "flatFieldMetadataMaps",
      "flatIndexMaps",
      "flatViewFilterMaps",
      "flatViewGroupMaps",
      "flatViewMaps",
      "flatViewFieldMaps",
      "flatObjectMetadataMaps"
    ],
    "actions": [
      {
        "type": "update_field",
        "fieldMetadataId": "",
        "objectMetadataId": "",
        "updates": [
          {
            "from": "'email'",
            "to": "'EMAIL'",
            "property": "defaultValue"
          },
          {
            "from": [
              {
                "color": "green",
                "id": "",
                "label": "Email",
                "position": 0,
                "value": "email"
              },
              {
                "color": "blue",
                "id": "",
                "label": "SMS",
                "position": 1,
                "value": "sms"
              }
            ],
            "to": [
              {
                "color": "green",
                "id": "",
                "label": "Email",
                "position": 0,
                "value": "EMAIL"
              },
              {
                "color": "blue",
                "id": "",
                "label": "SMS",
                "position": 1,
                "value": "SMS"
              }
            ],
            "property": "options"
          }
        ]
      }
    ],
    "workspaceId": "e"
  }
}
```

### MessageParticipantRole
```json
{
  "status": "success",
  "workspaceMigration": {
    "relatedFlatEntityMapsKeys": [
      "flatFieldMetadataMaps",
      "flatIndexMaps",
      "flatViewFilterMaps",
      "flatViewGroupMaps",
      "flatViewMaps",
      "flatViewFieldMaps",
      "flatObjectMetadataMaps"
    ],
    "actions": [
      {
        "type": "update_field",
        "fieldMetadataId": "",
        "objectMetadataId": "",
        "updates": [
          {
            "from": "'from'",
            "to": "'FROM'",
            "property": "defaultValue"
          },
          {
            "from": [
              {
                "color": "green",
                "id": "",
                "label": "From",
                "position": 0,
                "value": "from"
              },
              {
                "color": "blue",
                "id": "",
                "label": "To",
                "position": 1,
                "value": "to"
              },
              {
                "color": "orange",
                "id": "",
                "label": "Cc",
                "position": 2,
                "value": "cc"
              },
              {
                "color": "red",
                "id": "",
                "label": "Bcc",
                "position": 3,
                "value": "bcc"
              }
            ],
            "to": [
              {
                "color": "green",
                "id": "",
                "label": "From",
                "position": 0,
                "value": "FROM"
              },
              {
                "color": "blue",
                "id": "",
                "label": "To",
                "position": 1,
                "value": "TO"
              },
              {
                "color": "orange",
                "id": "",
                "label": "Cc",
                "position": 2,
                "value": "CC"
              },
              {
                "color": "red",
                "id": "",
                "label": "Bcc",
                "position": 3,
                "value": "BCC"
              }
            ],
            "property": "options"
          }
        ]
      }
    ],
    "workspaceId": ""
  }
}
```

### Workspace member number format labels
```json
{
  "status": "success",
  "workspaceMigration": {
    "relatedFlatEntityMapsKeys": [
      "flatFieldMetadataMaps",
      "flatIndexMaps",
      "flatViewFilterMaps",
      "flatViewGroupMaps",
      "flatViewMaps",
      "flatViewFieldMaps",
      "flatObjectMetadataMaps"
    ],
    "actions": [
      {
        "type": "update_field",
        "fieldMetadataId": "",
        "objectMetadataId": "",
        "updates": [
          {
            "from": [
              {
                "color": "turquoise",
                "id": "",
                "label": "System",
                "position": 0,
                "value": "SYSTEM"
              },
              {
                "color": "blue",
                "id": "",
                "label": "Commas and dot (1,234.56)",
                "position": 1,
                "value": "COMMAS_AND_DOT"
              },
              {
                "color": "green",
                "id": "",
                "label": "Spaces and comma (1 234,56)",
                "position": 2,
                "value": "SPACES_AND_COMMA"
              },
              {
                "color": "orange",
                "id": "",
                "label": "Dots and comma (1.234,56)",
                "position": 3,
                "value": "DOTS_AND_COMMA"
              },
              {
                "color": "purple",
                "id": "",
                "label": "Apostrophe and dot (1'234.56)",
                "position": 4,
                "value": "APOSTROPHE_AND_DOT"
              }
            ],
            "to": [
              {
                "color": "turquoise",
                "id": "",
                "label": "System",
                "position": 0,
                "value": "SYSTEM"
              },
              {
                "color": "blue",
                "id": "",
                "label": "Commas and dot",
                "position": 1,
                "value": "COMMAS_AND_DOT"
              },
              {
                "color": "green",
                "id": "",
                "label": "Spaces and comma",
                "position": 2,
                "value": "SPACES_AND_COMMA"
              },
              {
                "color": "orange",
                "id": "",
                "label": "Dots and comma",
                "position": 3,
                "value": "DOTS_AND_COMMA"
              },
              {
                "color": "purple",
                "id": "",
                "label": "Apostrophe and dot",
                "position": 4,
                "value": "APOSTROPHE_AND_DOT"
              }
            ],
            "property": "options"
          }
        ]
      }
    ],
    "workspaceId": ""
  }
}
```
2025-12-09 14:09:48 +01:00
EtienneandGitHub be91d870f9 Fix - revert standard sync logic on index + fix command (#16421) 2025-12-09 12:54:01 +00:00
07cfaa78ef Fix unique standard field (#16371)
Fixes https://github.com/twentyhq/twenty/issues/15925

- update field metadata update logic
- uniformize the way index are named
- command to migrate v1-named unique index
- add integration testing

---------

Co-authored-by: prastoin <paul@twenty.com>
2025-12-08 18:05:28 +00:00
Raphaël BosiandGitHub 5fb7e76005 Migrate page layout to v2 (#16364) 2025-12-08 14:11:24 +00:00