Commit Graph

419 Commits

Author SHA1 Message Date
martmull a68e05682b Serverless built updates (#17351)
follow up of https://github.com/twentyhq/twenty/pull/17317
2026-01-22 15:04:29 +00:00
Etienne 0459f25dec Files v2 - Add new workspace field file upload resolver (#17325) 2026-01-22 13:15:52 +00:00
Abdul Rahman aff577689f Add syncable NavigationMenuItem entity to core schema (#17232)
Implements a new syncable `navigationMenuItem` entity in the core schema
to replace the workspace `favorite` entity.

## Next Steps
- Frontend integration ([separate
PR](https://github.com/twentyhq/twenty/pull/17268))
- Data migration (separate PR)
2026-01-22 12:48:51 +00:00
martmull f92c8a98a4 2114 extensibility manage serverless execution from built code (#17317)
Summary

- Serverless functions are now built when created/updated instead of at
execution time
  - Added builtHandlerPath field to track pre-built function artifacts
- Renamed base-typescript-project to seed-project with pre-built ESM
output included
- Renamed file folder enums for consistency (Functions → BuiltFunction,
SourceCode → Source)
  - supports backwards compatibility with existing serverless functions

Tested with all combinations
- storage : local driver and S3 driver
- serverless : local driver and lambda driver
2026-01-22 12:56:44 +01:00
Paul Rastoin 6aa43b68f7 Identification cleanup (#17301)
# Introduction

following https://github.com/twentyhq/twenty/pull/17279
As we've finally identified all the syncable metadata entities, which
means they're expected to have non nullable applicationId and
universalIdentifier at pg_level we can remove previous retro comp
universalIdentifier fallbacking and update the dto too

~~This needs IdentifyRemainingEntitiesMetadataCommand and
MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand
to be run~~
```ts
[Nest] 197  - 01/21/2026, 3:08:35 PM     LOG [MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand] Successfully run MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand
```
2026-01-21 16:00:23 +00:00
Félix Malfait 3ed67b825e feat: implement generic many-to-many junction relation support (#16820)
## Overview

This PR implements **generic many-to-many relation support** through
junction tables (also known as associative entities or join tables).
This replaces the need for hardcoded taskTarget/noteTarget logic and
provides a flexible foundation for modeling complex entity
relationships.

## Architecture

### Data Model

Many-to-many relationships are implemented using a **junction object
pattern**:

```
┌─────────┐       ┌──────────────────┐       ┌─────────┐
│  Pet    │──────>│   PetRocket      │<──────│ Rocket  │
│         │ 1:N   │  (junction)      │  N:1  │         │
│ rockets ├───────┤ pet    : Pet     ├───────┤         │
└─────────┘       │ rocket : Rocket  │       └─────────┘
                  └──────────────────┘
```

The junction object (PetRocket) has:
- A `MANY_TO_ONE` relation to **Pet** (the source)
- A `MANY_TO_ONE` relation to **Rocket** (the target)

The source object (Pet) has a `ONE_TO_MANY` relation pointing to the
junction, with **field settings** that specify which target field to
follow.

### Field Settings Schema

Junction configuration is stored in `FieldMetadataRelationSettings`:

```typescript
{
  relationType: "ONE_TO_MANY",
  // Points to the target field on the junction object
  junctionTargetFieldId?: string;      // For regular relations
  junctionTargetMorphId?: string;      // For polymorphic relations
}
```

**Two configuration modes:**
1. **`junctionTargetFieldId`** - References a specific `RELATION` field
on the junction
2. **`junctionTargetMorphId`** - References a `morphId` group for
polymorphic targets (e.g., link to Person OR Company)

### GraphQL Query Generation

When a junction relation is detected, the GraphQL fields are generated
to fetch the nested target:

```graphql
query GetPetWithRockets {
  pet(id: "...") {
    rockets {           # ONE_TO_MANY to junction
      id
      rocket {          # Target field on junction
        id
        name
        __typename
      }
    }
  }
}
```

For polymorphic junction targets:
```graphql
caretakerPerson { id, name }
caretakerCompany { id, name }
```

## Frontend Architecture

### Display Flow

1. **Detection**: `hasJunctionConfig()` checks if field has junction
settings
2. **Config Resolution**: `getJunctionConfig()` resolves junction object
metadata and target fields
3. **Record Extraction**: `extractTargetRecordsFromJunction()` extracts
target records from junction records
4. **Rendering**: Target records displayed as chips (not junction
records)

### Edit Flow

1. **Picker Opening**: Initializes the multi-record picker with:
   - Searchable object types (derived from junction target fields)
   - Pre-selected items (extracted from existing junction records)
   
2. **Selection Handling**: Manages create/delete of junction records:
   - **Select**: Creates new junction record with source + target IDs
   - **Deselect**: Finds and deletes the junction record
- **Optimistic Updates**: Manually updates Recoil store before API call

### Key Trade-offs

| Decision | Trade-off |
|----------|-----------|
| Junction records managed manually | More control over optimistic
updates, but requires manual cache management |
| Settings stored per-field | Flexible (same junction can power
different views), but requires UI to configure |
| Polymorphic via morphId groups | Supports N target types, but adds
query complexity |
| Feature flag gated | Safe rollout, but requires flag management |

## Backend Changes

- **Validation**: Junction target field must exist and be a valid
`MANY_TO_ONE` relation
- **Settings**: Extended `FieldMetadataRelationSettings` type with
junction fields
- **Dev Seeder**: Added sample junction objects (PetRocket,
EmploymentHistory, PetCareAgreement) for testing

## How to Test

1. Enable the `IS_JUNCTION_RELATIONS_ENABLED` feature flag
2. Create objects with junction pattern (Pet → PetRocket → Rocket)
3. Configure the junction target in field settings (advanced mode)
4. Verify:
- Display shows target objects (Rockets), not junction records
(PetRockets)
   - Picker allows selecting/deselecting targets
   - Changes persist correctly



https://github.com/user-attachments/assets/d04f057a-228c-4de8-af48-76bb2d72cac1

---------

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


To do in next PRs : 
- Backend : 
-- new workspaceFile controller (for download) & new workspaceFile
upload resolver (for upload)
-- pre-hook/post-hook to ensure fileId existence + listener to ensure
cleaning
- Frontend : FILES field display/edit in table view, record, ...
2026-01-20 17:03:49 +00:00
Weiko b6635ba272 Add RLS Entitlement check (#17179)
## Context
- Add RLS entitlement to billing
- Check value in the backend (for RLS predicate entity
queries/mutations)
- Expose billingEntitlements to the API inside currentWorkspace to check
available features to the workspace and display the role components
accordingly
- Cleanup RLS when plan changes back to one without RLS.

This should cover almost everything, imho we don't need to check in the
ORM because => We can't create RLS without the correct PLAN and
switching back to a PLAN without RLS deletes existing RLS through
stripes webhooks
2026-01-20 16:06:37 +00:00
martmull 02a181a49f Add endpoint to upload application file (#17270)
As title
2026-01-20 14:10:34 +00:00
martmull 801878cb2b 2091 extensibility twenty sdk add command twenty app function logs and twenty app function test (#17278)
add `function:logs` and `function:execute` cli commands
2026-01-20 14:10:01 +00:00
Raphaël Bosi d0bc8b9ffe [DASHBOARDS] Move all the graph computing logic to the backend (#17189)
- Create resolvers for each type of charts which needs data
transformation after the group by operation: Bar Chart, Line Chart and
Pie Chart
- Move all the utils to the backend and refactored some into services

This allows all the computation to be done in the backend, improving
performances in the frontend.
2026-01-19 17:25:45 +00:00
Abdul Rahman 5a617e4718 Add command menu item entity (#17181) 2026-01-16 19:02:07 +00:00
Charles Bochet 5fc4e810f7 Front Extensibility: Introduce Front Component Entity (#17175)
As part of the extensibility effort, we are introducing a new engine
entity called "Front Component". This represents a dynamic react
component that will be rendered in CommandMenu actions or in PageLayout
widgets

This PR introduce the entity and all the necessary boilerplate to make
it syncable and cachable in the engine
2026-01-16 17:23:46 +01:00
Etienne 76cbe59929 File v2 - update core.file table (#17172)
For the following, I'll create the issues first
2026-01-16 15:59:39 +00:00
martmull 1917c1c9b9 Add forwardedRequestHeaders in routeTriggers (#17151)
- add `forwardedRequestHeaders` `string[]` column in `core.routeTrigger`
- filter request headers and forward filtered headers to function
payload (avoid spreading unexpectedly token or cookie)
- add `forwardedRequestHeaders` option in twenty-sdk `defineFunction`
util

BREAKING for actual routeTrigger payload but only 16 to migrate in
production
2026-01-16 09:19:28 +00:00
Weiko 8413c6f3dd Fix insert new record with RLS (#17164)
## Context
Now that RLS predicates are applied, creating a record through the FE
(which is empty by default) is failing if your role has predicates and
your input does not respect them (which will always be true since, as
said above, input will be pretty much empty)

## Implementation
- Moved isMatching* filters to twenty-shared
- Implemented isMatchingRlsPredicates utils in the backend (ORM) to
check before insertion/update if the record is matching the current user
role Rls predicates, reusing the isMatching* filters utils moved to
twenty-shared
- Frontend now applies RLS predicates before creating a new record
(similarly to what we do with view filters)

Note:
It seems composite were not properly handled with view-filter insertion
logic, since I'm reusing the util for now, the issue remains for RLS and
will need to be addressed
2026-01-15 16:40:47 +00:00
Thomas Trompette 93aef30046 Add feature flag for sse (#17152)
As title
2026-01-14 14:20:45 +00:00
Thomas Trompette 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
Lucas Bordeau 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
Weiko 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
Raphaël Bosi 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
nitin 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
Thomas Trompette 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
Paul Rastoin 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
Weiko 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
Thomas Trompette 2c5a7570fc Clean workflow run stoppage flag (#16950)
Flag has never been removed. Feature allows to stop a running workflow
run.
2026-01-06 17:05:46 +01:00
Thomas Trompette 35c7687ed8 Publish batch events for sse subscriptions (#16943)
- publish batch events to avoid multiple redis / graphql sse
publications
- add event to the endpoint output
2026-01-06 13:22:14 +01:00
Raphaël Bosi c531cfe0a4 [DASHBOARDS] Manual and position-based sorting for chart widgets (#16794)
## Description

SELECT fields have a defined option order that users expect to see
reflected in charts.
This PR allows sorting by that position and also enables custom manual
ordering.

## Video QA

### Reordering on primary axis


https://github.com/user-attachments/assets/994f515e-19cb-4a5e-b745-e8c77e92ae0b


### Reordering on secondary axis


https://github.com/user-attachments/assets/444c16f2-1920-4dc4-8b42-312d520ab43b

Note: The colors in the graph will match the colors of the select
options, but this will be done in another PR

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Introduces new sort modes and UI for chart groupings, with full FE/BE
support and updated GraphQL schema.
> 
> - Extend `GraphOrderBy` with `FIELD_POSITION_ASC/DESC` and `MANUAL`;
add corresponding fields in configs: `primaryAxisManualSortOrder`,
`secondaryAxisManualSortOrder`, and `manualSortOrder` (pie)
> - New UI: dropdown options filtered by field type, icons, and a
draggable submenu (`ChartManualSortSubMenuContent`) to reorder select
options; integrates with widget edit flow
> - Sorting logic added/refactored: `sortChartData`,
`sortByManualOrder`, `sortBySelectOptionPosition`,
`sortLineChartSeries`, plus updates to bar/line/pie transformers to
honor new modes and manual orders
> - Default behaviors: select fields default to `FIELD_POSITION_ASC`;
query variable builders skip `orderBy` when using manual/position sorts
> - Update GraphQL generated types/fragments/queries and backend
DTOs/schemas to persist new fields; add tests for sorting utilities and
snapshots; add sorting icons in `twenty-ui`
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
78c9b56c0f1f2d45f7f8b270bb59ca599a005abe. 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>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2026-01-06 11:52:54 +01:00
Félix Malfait 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 Malfait 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
Abdul Rahman dff5e3cd7b feat: Add If/Else node (#16833)
Closes [#1265](https://github.com/twentyhq/core-team-issues/issues/1265)
2026-01-01 14:05:56 +00:00
Weiko 1d124a7a77 Enabled RLS seed dev (#16884)
And remove IS_GLOBAL_WORKSPACE_DATASOURCE_ENABLED

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Removes deprecated feature flag and enables RLS predicates in dev**
> 
> - Deletes `IS_GLOBAL_WORKSPACE_DATASOURCE_ENABLED` from server enum
and frontend generated GraphQL types
> - Updates dev seeder to enable
`IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED` instead of the removed flag
> - Adjusts tests and mocked `GlobalWorkspaceDataSource` defaults to
drop the removed flag
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7f4d5a401a42e46dfcc576161d4f8167544f4453. 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>
2026-01-01 13:55:46 +01:00
Weiko 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
fe955cc4588a92157afa6795fb574189a4be1e93. 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 Rastoin 1128331cc1 Fix field item type tag (#16860)
# Introduction
This has been fixed on main already 1 hour ago, this PR now only passes
the field application id instead of the object applicationId that could
be different for example when creating a custom field on a standard
object

For the moment not introducing any logic around application integrity
directly and still relying on the isCustom and standardId definition
This will have to be refactored once we deprecate the standardId
2025-12-30 15:02:07 +00:00
Paul Rastoin 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
Paul Rastoin 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
github-actions[bot] ee0e2ed854 i18n - translations (#16832)
Created by Github action

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: github-actions <github-actions@twenty.com>
2025-12-29 11:01:07 +01:00
Félix Malfait 1b6a0cd05a fix(billing): redirect to Stripe payment method setup when subscribing without payment method (#16827)
## Summary

When users click 'Subscribe Now' during a trial period without a payment
method configured, they previously saw an unhelpful error message: "No
payment method found. Please update your billing details."

This PR improves the UX by redirecting users directly to Stripe's
billing portal payment method update flow, where they can add their
payment information. After adding a payment method, users are redirected
back to the billing settings page and can click 'Subscribe Now' again to
successfully activate their subscription.

## Changes

### Backend
- **stripe-billing-portal.service.ts**: Added
`createBillingPortalSessionForPaymentMethodUpdate` method that creates a
Stripe billing portal session with `flow_data.type:
'payment_method_update'`
- **billing-portal.workspace-service.ts**: Added
`computeBillingPortalSessionURLForPaymentMethodUpdate` method to build
the portal URL
- **billing-end-trial-period.output.ts**: Added optional
`billingPortalUrl` field to the GraphQL output DTO
- **billing-subscription.service.ts**: Modified `endTrialPeriod` to
return `stripeCustomerId` when no payment method exists
- **billing.resolver.ts**: Updated resolver to orchestrate billing
portal URL generation when no payment method

### Frontend
- **useEndSubscriptionTrialPeriod.ts**: Redirect to billing portal URL
instead of showing error snackbar
- **endSubscriptionTrialPeriod.ts**: Added `billingPortalUrl` to
mutation response fields

## User Flow

1. User clicks "Subscribe Now" during trial
2. Backend checks for payment method
3. If no payment method → redirect to Stripe billing portal payment
method update page
4. User adds payment method in Stripe
5. User is redirected back to `/settings/billing`
6. User clicks "Subscribe Now" again to activate subscription
2025-12-29 05:39:53 +01:00
Félix Malfait 7021a51747 feat(billing): implement credit rollover from one billing period to another (#16802)
## Summary
This PR implements credit rollover functionality for billing, allowing
unused credits from one billing period to carry over to the next (capped
at the current period's subscription tier cap).

## Changes

### New Services
- **StripeCreditGrantService**: Interacts with Stripe's Billing Credits
API to create credit grants, retrieve customer credit balances, and void
grants
- **BillingCreditRolloverService**: Contains the rollover logic -
calculates unused credits and creates new grants for the next period
- **BillingWebhookCreditGrantService**: Handles
`billing.credit_grant.created` and `billing.credit_grant.updated`
webhooks to update billing alerts

### Modified Services
- **StripeBillingAlertService**: Updated to include credit balance when
calculating usage threshold alerts
- **BillingUsageService**: Returns rollover credits to the frontend for
display
- **BillingSubscriptionService**: Queries credit balance when creating
billing alerts
- **BillingWebhookInvoiceService**: Triggers rollover processing on
`invoice.finalized` webhook

### Frontend
- Updated `SettingsBillingCreditsSection` to display base credits,
rollover credits, and total available
- Updated GraphQL query to fetch new `rolloverCredits` and
`totalGrantedCredits` fields

### Stripe SDK Upgrade
- Upgraded from v17.3.1 to v19.3.1 to get proper types for
billing.credit_grant events
- Fixed breaking changes: invoice.subscription path, subscription period
fields location, removed properties

## How it works

1. When `invoice.finalized` webhook is received for
`subscription_cycle`, the system:
   - Calculates usage from the previous period
   - Determines unused credits (tier cap - usage)
   - Caps rollover at current tier cap
   - Creates a Stripe credit grant with expiration at end of new period

2. When credit grants are created/updated/voided:
   - Billing alerts are recreated with the updated credit balance

3. The UI displays:
   - Base credits (from subscription tier)
   - Rollover credits (from previous periods)
   - Total available credits

## Edge Cases Handled
- Credit grant voided: `billing.credit_grant.updated` webhook triggers
alert update
- Credit grant expired: Stripe's `creditBalanceSummary` API excludes
expired grants
- No unused credits: Rollover service skips grant creation
- Customer ID as object: Controller extracts `.id` from expanded
customer
2025-12-28 15:42:18 +01:00
martmull 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
Marie 50b0665c44 Enable read on replica for all (#16740)
Removing the feature flag to enable read on replica for all workspaces.
It will still be possible to toggle off the feature by removing the env
variable `PG_DATABASE_REPLICA_URL`.
2025-12-22 14:32:04 +01:00
neo773 d30580fc4e remove IMAP_SMTP_CALDAV feature flag (#16695)
To be merged after 
https://github.com/twentyhq/twenty/pull/16479
https://github.com/twentyhq/twenty/pull/16694
2025-12-19 18:20:12 +01:00
Thomas Trompette 6355557356 [POC] Real-Time (#16633)
https://github.com/user-attachments/assets/3ad7a4f3-d08b-4a1c-b3c2-bb42ef9f3575

Real time POC.

Next steps:
- find out the correct API for subscription. Should be triggered
directly in query hooks (useFindManyRecords, useLazy...)
- improve query matching
2025-12-19 07:17:02 -10:00
Paul Rastoin 6f2ff06a35 Refactor workspace creation (#16689)
# Introduction
Created an env variable to will inject a feature flag during any new
workspace init to be created through v2
2025-12-19 12:47:31 +01:00
Marie afaf47cdf5 Read some endpoints on replica db (behind feature flag) (#16677)
Next steps: 
- move some workers' activities to replica db
2025-12-19 10:48:18 +01:00
Baptiste Devessier 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
martmull 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
nitin fc74a06f53 [Dashboards] add hide empty category option for pie charts (#16550)
closes
https://discord.com/channels/1130383047699738754/1445403391722520677


https://github.com/user-attachments/assets/980225a8-153e-4b49-89f7-5944227c8fdb


toggle label ie `Hide empty category` -- debatable
2025-12-15 15:40:46 +00:00
Félix Malfait 2e104c8e76 feat(ai): add code interpreter for AI data analysis (#16559)
## Summary

- Add code interpreter tool that enables AI to execute Python code for
data analysis, CSV processing, and chart generation
- Support for both local (development) and E2B (sandboxed production)
execution drivers
- Real-time streaming of stdout/stderr and generated files
- Frontend components for displaying code execution results with
expandable sections

## Code Quality Improvements

- Extract `getMimeType` to shared utility to reduce code duplication
between drivers
- Fix security issue: escape single quotes/backslashes in E2B driver env
variable injection
- Add `buildExecutionState` helper to reduce duplicated state object
construction
- Add `DEFAULT_CODE_INTERPRETER_TIMEOUT_MS` constant for consistency
- Fix lingui linting warning and TypeScript theme errors in frontend

## Test Plan

- [ ] Test code interpreter with local driver in development
- [ ] Test code interpreter with E2B driver in production environment
- [ ] Verify streaming output displays correctly in chat UI
- [ ] Verify generated files (charts, CSVs) are uploaded and
downloadable
- [ ] Test file upload flow (CSV, Excel) triggers code interpreter

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Updates generated i18n catalogs for Polish and pseudo-English, adding
strings for code execution/output (code interpreter) and various UI
messages, with minor text adjustments.
> 
> - **Localization**:
> - **Generated catalogs**: Refresh `locales/generated/pl-PL.ts` and
`locales/generated/pseudo-en.ts`.
> - Add strings for code execution/output (e.g., code, copy code/output,
running/waiting states, download files, generated files, Python code
execution).
> - Include new UI texts (errors, prompts, menus) and minor text
corrections.
>   - No changes to `pt-BR`; other files unchanged functionally.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
befc13d02c21e5a6647bc1aa6daa2a89f60b7ef8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
2025-12-15 16:11:24 +01:00
Félix Malfait 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