Commit Graph
3383 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
martmullandGitHub f894f6b1c4 Fix universalIdentifier ignored when creating object (#17158)
As title
2026-01-15 08:41:44 +00:00
Thomas TrompetteandGitHub 6e53f5ab92 Throw 400 for webhook triggering deleted workspaces + enqueue workflows by batches (#17154)
Fixes https://github.com/twentyhq/twenty/issues/17027

Fixes https://github.com/twentyhq/twenty/issues/16824
2026-01-14 17:35:05 +00:00
Thomas TrompetteandGitHub 79e0207efa Filter valid fields in record steps (#17145)
Fixes https://github.com/twentyhq/twenty/issues/16775

When a field is deleted from the model, the workflow action step still
stores the deleted field name in `step.settings.input.objectRecord`.

We need to filter out the fields that are not valid anymore. This logic
existed before but had been removed with the migration to tool services.
2026-01-14 14:43:35 +00:00
Thomas TrompetteandGitHub 93aef30046 Add feature flag for sse (#17152)
As title
2026-01-14 14:20:45 +00:00
Paul RastoinandGitHub 9e4247c934 Clean soft deleted suspended workspace command and ignore-grace-period flag (#17144)
# Introduction

In the https://github.com/twentyhq/core-team-issues/issues/1989 's
context we will apply migration through an upgrade command post entity
backfill to fit the applied constraint. But suspended soft deleted
workspace are not included in the upgrade workspace batches

In order to be able to pass the constraint in production, discussed with
@FelixMalfait, we will manually clear all the currently suspended and
soft deleted workspace ignore their grace period

## Force mode
When running the command in force it will ignore the limit per execution
( which really serve the cron job ) and the grace period

## Test
Tested on a production extract
2026-01-14 14:15:15 +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
neo773andGitHub 0412ce2cda IMAP Error handling enhancement and fix revoked authentication edge case (#17133)
## Changes

- Removed complex retry logic in `ImapClientProvider` by delegating to
root orchestrator
- Added `parseImapAuthenticationError` for handling revoked
authentication credentials previously the code existed in
`parse-imap-error.util` but it didn't belong there and nor was not used
in `ImapClientProvider` causing revoked channels to be stuck in limbo
- Removed `parseImapError` from `*-error-handler.service.ts `
- Created `isImapNetworkError`  for consistency with Gmail and Microsoft
- `isImapNetworkError` is called at utility level for consistency
2026-01-14 13:00:43 +00:00
Thomas TrompetteandGitHub ec87b29286 Move query matching before publication (#17121)
- new channel EVENT_STREAM_CHANNEL based on event stream id
- on event, perform the matching and publish only to the right streams
- store a list of active streams per workspace
- store the user id along with the queries for each stream

Bonus:
- remove onSubscriptionMatch
2026-01-14 12:29:12 +00:00
Paul RastoinandGitHub 70704264ac Fix dev seed page layout cache invalidation (#17141)
# Introduction

followup https://github.com/twentyhq/twenty/pull/16962

Root cause: as now the twenty standard app installation in seeded
workspace invalidates and set the page layout-xxx caches the inserted
through direct repo access data in the prefill legacy page layout
methods do not interact with the cache
The cache being set in prior when recompute does not result in db
introspection as before as when was unset
2026-01-14 12:08:51 +00:00
neo773andGitHub b79056b3a2 refactor google refresh token service error handling (#17127)
Refactors to be consistent with Microsoft service
Handles scenarios like temporary error which was not handled before
Moved `IsGmailNetworkError` from root orchestrator to driver level
2026-01-13 18:24:53 +00:00
Raphaël BosiandGitHub f793faae2b 17042 followups (#17122)
Followups after @Weiko review on
https://github.com/twentyhq/twenty/pull/17042
2026-01-13 16:25:30 +00:00
Paul RastoinandGitHub 46cf551281 Invalidate legacy cache after flats (#17126)
# Introduction

Some legacy caches are based on the flat ones
So we need to seq invalidate before invalidating others as it could
result in inter dep cache invalidation race condition
2026-01-13 16:07:27 +00:00
4a3cc0aeb8 i18n - translations (#17125)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-13 16:38:18 +01:00
martmullandGitHub d55b83375d Allow app to extend object (#17116)
- exports `extendObject` utils from `twenty-sdk`
- define `*.object-extension.ts` filename pattern to extend and object
- handle object-extension configs in manifest
2026-01-13 15:07:14 +00:00
Paul RastoinandGitHub f1be7129cb Allow isUnique mutation on standard field (#17120)
# Introduction
As we've just
[identified](https://github.com/twentyhq/twenty/pull/16981) the standard
field metadata in production we can not enable the is unique comparison
even for standard entities
2026-01-13 13:28:50 +00:00
db87da162c i18n - translations (#17119)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-13 11:21:29 +01:00
b0d6571469 Improve Japanese translations (#16979)
The current Japanese translations are severely lacking. My company
(based in Tokyo) uses Japanese as its main language. I've gone through
and corrected/standardized everything. This is good enough to merge as a
starting point.

Includes `lingui compile` for the changes.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Major localization refresh focused on Japanese.
> 
> - Rewrites and standardizes `ja-JP` message strings (clearer phrasing,
consistent terminology, corrected placeholders/punctuation)
> - Regenerates compiled Lingui locale bundles; updates `ja-JP.ts` and
`ko-KR.ts` outputs
> - No runtime logic changes; scope limited to generated i18n resources
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3365dcdac6. 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@twenty.com>
2026-01-13 10:28:45 +01: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
Lucas BordeauandGitHub 04a370e043 Implemented SSE subscription mechanism on the frontend (#17017)
This PR is a follow-up of https://github.com/twentyhq/twenty/pull/16966
and implements a new mechanism to handle SSE events.

It creates only one event stream per browser tab, then use mutations to
tell the backend which query to listen to, without re-mounting the event
stream connexion.

Then each event that comes from this unique subscription is then
dispatched in a new JavaScript CustomEvent, per queryId, on which
specific hooks add an event listener.

This PR introduces the generic tooling as well as the handling of update
events on table.
2026-01-12 18:58:46 +01:00
1c2fda30bd i18n - translations (#17106)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-12 18:58:01 +01: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
493f0575ea i18n - translations (#17097)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-12 14:29:26 +01:00
Raphaël BosiandGitHub 655f1eef5f [DASHBOARDS] Allow dashboards to be restored (#17042)
This PR introduces a few changes:
- Add three actions: see deleted dashboards, destroy dashboard and
restore dashboard
- Remove the soft delete and restore on all the page layout entities
- Cascade the destruction of a dashboard to a page layout

Video QA:


https://github.com/user-attachments/assets/ab993b11-dd9c-4e88-880c-92691a521cc2
2026-01-12 12:59:17 +00:00
MarieandGitHub 3ada8e5168 [Extensibility] Support relation fields (#17056)
Closes https://github.com/twentyhq/core-team-issues/issues/2043
2026-01-12 12:54:30 +00:00
Paul RastoinandGitHub 91b788ee09 [REQUIRES_FIELDS_CACHE_FLUSH]Fix field entity to flat field transpiler (#17096)
Following https://github.com/twentyhq/twenty/pull/16981

UniversalIdentifier is now required in the entity so no need to fallback
it
2026-01-12 12:49:07 +00:00
nitinandGitHub 342ae995d9 Add error boundary on widget renderer and minor widget seed fix (#17058)
closes https://github.com/twentyhq/twenty/issues/16896 and
https://github.com/twentyhq/core-team-issues/issues/2050

should error be Invalid Configuration or something else?
2026-01-12 12:02:58 +00:00
238e6d5cda Common api - chores (#17051)
Remove refacto-common TODO

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-12 11:37:29 +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
Félix MalfaitandGitHub 57363c2127 Fix orderBy columns missing from SELECT in DISTINCT subquery (#17079)
## Description

Fixes a bug where queries with relation field + scalar field ordering
would fail with:
```
column distinctAlias.person_position does not exist
```

## Root Cause

When a GraphQL query orders by columns that are **not in the selected
fields**, TypeORM's DISTINCT subquery fails because it expects those
columns in the inner SELECT with alias format (e.g., `person_position`).

The issue only manifests when:
1. A filter is applied (triggers DISTINCT path in TypeORM)
2. OrderBy includes columns NOT in the GraphQL selection
3. Example: query selects only `id`, but orders by `position`

## The Fix

`addRelationOrderColumnsToBuilder` now accepts `columnsToSelect` and
adds orderBy columns via `addSelect()` only if they're **NOT** already
in the selected columns:

- **Relation orderBy columns**: Always added (never in columnsToSelect)
- **Main entity orderBy columns**: Added only when not already selected

This ensures all orderBy columns are present in TypeORM's inner SELECT
for the DISTINCT subquery.

## Test Plan

Added integration test for the exact failing scenario:
- Filter with `neq` (triggers DISTINCT path)
- Multiple orderBy: relation field + scalar field  
- Minimal field selection (only `id`, not `position`)

## Related

Regression introduced in #17021 which added nested sort support.
2026-01-11 14:19:05 +01:00
20f62e05f5 fix(search): add support for searching by additional emails, phones, and secondary links (#17034)
## Summary
- Add `additionalEmails` (EMAILS type) to tsvector search expression
- Add `additionalPhones` (PHONES type) to tsvector search expression  
- Add `secondaryLinks` (LINKS type) to tsvector search expression

This enables searching for people/companies by their secondary contact
information, not just primary values.

## Test plan
- [x] Unit tests for all three composite field types (16 tests passing)
- [x] Integration tests for searching by secondary email, work email,
partial domain
- [x] Integration tests for searching by additional phone numbers
- [x] Integration test for searching by secondary link URL
- [x] Lint passes

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-10 15:24:46 +00:00
Thomas TrompetteandGitHub 3acc87a620 [SSE] Add backend for SSE subscriptions (#17022)
- moved a few gql types to twenty shared to re-use in server
- added a new endpoint, onEventSubscription that expect a streamId to
create a connection
- two new endpoints to store queries in Redis
- updated the existing batch channel to directly use object record type
2026-01-10 14:44:02 +00:00
neo773andGitHub 87fb25c703 IMAP edge cases (#17065)
Fixes IMAP edge case. We had a maximum call stack reached crash if the
array was very large for some folders. Plus some minor perf improvement.


https://twenty-v7.sentry.io/issues/6997180505/events/652c69da1be944aab1c87ac2e6a06c30/
2026-01-10 14:26:07 +00:00
Félix MalfaitandGitHub a8331dc43e feat: add case-insensitive sorting for text fields (#17023)
## Context

Text fields were being sorted case-sensitively on the backend (e.g.,
'Apple', 'apple', 'Banana' would sort as 'Apple', 'Banana', 'apple').
This resulted in unexpected sorting behavior that differed between the
frontend Apollo cache sorting and backend database sorting.

## Changes

### Backend (packages/twenty-server)

- **`graphql-query-order.parser.ts`**:
- Added `shouldUseCaseInsensitiveOrder()` helper that returns `true` for
TEXT, SELECT, and MULTI_SELECT fields
- Added `buildOrderByColumnExpression()` method that wraps column
expressions with `LOWER()` for case-insensitive sorting
- Updated `parse()` and `parseObjectRecordOrderByForScalarField()` to
use the new helpers
- Updated `parseObjectRecordOrderByForRelationField()` to apply LOWER()
to nested text fields

- **`parse-composite-field-for-order.util.ts`**:
- Added `shouldUseCaseInsensitiveOrder()` helper for composite subfields
- Updated composite field parsing to apply `LOWER()` to subfields of
type TEXT (e.g., `name.firstName`, `name.lastName`)

### Frontend (packages/twenty-front)

- **`sort.ts`**:
- Updated `sortAsc()` to use case-insensitive comparison
(`toLowerCase()`) for string values
- `sortDesc()` automatically benefits from this since it delegates to
`sortAsc()`
  - Ensures Apollo cache sorting matches backend behavior

## Example

Before:
```sql
ORDER BY "person"."name" ASC
```
Result: ['Apple', 'Banana', 'apple', 'cherry']

After:
```sql
ORDER BY LOWER("person"."name") ASC
```
Result: ['apple', 'Apple', 'Banana', 'cherry']

## Testing

- Manual testing of sorting on People and Companies views
- Verified frontend cache sorting matches backend results
2026-01-10 14:05:56 +01:00
Félix MalfaitandGitHub 1a5675d63e feat: add sorting on relation fields (Many-to-One) (#17021)
## Summary

This PR enables sorting records by fields of related objects. For
example, sorting **People by their Company's name**.

### Before
Only scalar and composite fields could be sorted. Relation fields showed
in the sort dropdown but produced errors.

### After
Many-to-One relation fields can now be sorted using the related object's
**label identifier field** (e.g., Company's `name`).

---

## Changes

### Frontend
- Added `RELATION` to sortable field types (restricted to `MANY_TO_ONE`
relations)
- New `getOrderByForRelationField()` generates nested orderBy structures
using the related object's label identifier
- Updated `turnSortsIntoOrderBy()` to handle relation fields by looking
up related object metadata

### Backend
- Extended `GraphqlQueryOrderFieldParser.parse()` to detect nested
relation ordering like `{ company: { name: 'AscNullsLast' } }`
- Returns `ParseOrderByResult` containing both `orderBy` conditions and
`relationJoins` info
- Added LEFT JOINs for relation ordering in `applyOrderToBuilder()`
- Added `addRelationOrderColumnsToBuilder()` for TypeORM DISTINCT
compatibility

### Tests
- Added unit tests for `filterSortableFieldMetadataItems`,
`getOrderByForRelationField`, and `turnSortsIntoOrderBy`
- Added integration tests covering ascending/descending order and
composite label identifiers

---

## TypeORM Bug Workaround

We encountered a significant TypeORM limitation when implementing this
feature. When using `getMany()` with `ORDER BY` on joined relation
columns, TypeORM generates a DISTINCT subquery that has specific
requirements:

### Issue 1: Alias Parsing
TypeORM's `orderBy()` method fails with **"alias not found"** when using
quoted SQL identifiers like `"company"."name"`. TypeORM internally
expects unquoted property paths (e.g., `company.name`) for its alias
resolution mechanism.

### Issue 2: setFindOptions Clears addSelect
`setFindOptions({ select })` **clears any previously added `addSelect()`
columns**. This caused `"column distinctAlias.company_name does not
exist"` errors because the relation columns needed for ORDER BY were
being removed.

### Solution
We split the logic into two methods:
1. `applyOrderToBuilder()` - adds JOINs and ORDER BY (before
`setFindOptions`)
2. `addRelationOrderColumnsToBuilder()` - adds relation columns for
SELECT (AFTER `setFindOptions`)

This ensures the relation columns are present in the final SQL query's
SELECT clause with the proper underscore aliases (`company_name`) that
TypeORM's DISTINCT subquery expects.

**Related TypeORM issue**:
https://github.com/typeorm/typeorm/issues/9921

---

## Screenshots/Demo

_Add screenshots if applicable_
2026-01-10 11:02:16 +01:00
9b6eb8b80a fix onboarding for messaging (#16729)
Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-09 20:17:04 +00:00
EtienneandGitHub f3d89ca9b9 Fix cleaning command (#17040)
Previous behavior:

Used billingSubscription.updatedAt (when the subscription record was
last modified)
Problem: updatedAt changes for ANY update, not just status changes,
making it unreliable for tracking when payment problems started

Current behavior:

Uses currentPeriodStart when subscription status is Unpaid or Canceled
Why it works: WORKSPACE_INACTIVE_DAYS_BEFORE_SOFT_DELETION is shorter
than the minimum billing interval (1 month). Then if a workspace is
unpaid for the entire current billing period, it will always exceed the
deletion threshold before the next period starts

Ideal fix:
Track workspace.suspendedAt explicitly, giving you the exact timestamp
of when payment problems began, regardless of billing periods.
2026-01-09 18:11:41 +00:00
Abdul RahmanGitHubcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
151731c05d If else node followup changes (#16974)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-09 17:20:58 +00:00
neo773andGitHub a0b2aa207f Fix messaging 404 handling (#17041)
`MessageImportExceptionHandlerService.handleSyncCursorErrorException()`
was calling `messageChannelSyncStatusService.markAsFailed()`
instead of

`messageChannelSyncStatusService.resetAndMarkAsMessagesListFetchPending()`

Also adds a new command `MessagingTriggerMessageListFetchCommand` for
faster local development speed
2026-01-09 16:35:12 +00:00
52e859e5a7 i18n - translations (#17048)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-09 15:38:08 +01: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
neo773andGitHub a5eae50c66 Migrate MicrosoftAPIRefreshAccessTokenService to @azure/msal-node (#16954) 2026-01-08 17:18:35 +00:00
85a7f6548e i18n - translations (#17025)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 17:27:35 +01: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
3e08f295d5 i18n - translations (#17007)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 10:50:39 +01: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