Commit Graph

1822 Commits

Author SHA1 Message Date
github-actions[bot] d444648cc0 i18n - translations (#18127)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-20 14:41:58 +01:00
Félix Malfait ec57d3fe0f Fix flaky 2FA encryption test for AES-256-CBC wrong-key behavior (#18126)
## Summary

- Fixes a flaky test in `simple-secret-encryption.util.spec.ts` that
fails ~1 in 256 runs
- AES-256-CBC doesn't guarantee wrong-key decryption throws — PKCS7
padding validation is probabilistic. When padding accidentally looks
valid, decryption silently returns garbage instead of throwing.
- Changed the test to verify the correct security property: wrong-key
decryption must never return the original secret (both throw and garbage
are acceptable)
- Audited both production `decryptSecret` call sites in
`two-factor-authentication.service.ts` — they always use the correct
key, so end users are not affected

## Test plan

- [x] Test passes 5/5 consecutive runs locally
- [x] Lint passes


Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-20 14:41:31 +01:00
Félix Malfait b107020ad3 Fix search edge case with permissions (#18123)
Fix E2E tests

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-20 14:08:20 +01:00
Paul Rastoin bf1e0d0811 Typecheck main sdk (#18124) 2026-02-20 13:47:57 +01:00
Félix Malfait 66da296799 Unify MCP into single endpoint with lazy tool discovery (#18113)
## Summary

- Consolidates the MCP server from two endpoints (`/mcp` +
`/mcp/metadata`) into a **single `POST /mcp`** endpoint exposing five
high-level tools: `get_tool_catalog`, `learn_tools`, `execute_tool`,
`load_skills`, and `search_help_center`
- Fixes **DATABASE_CRUD tools not accessible via API key auth** by
removing an unnecessary `userId`/`userWorkspaceId` guard in
`DatabaseToolProvider` and threading `ApiKeyWorkspaceAuthContext`
through the tool context chain
- Improves tool descriptions with **STEP 1/2/3 workflow guidance** so AI
clients follow the correct discovery flow (catalog → learn → execute)
instead of guessing tool names
- Simplifies the **frontend AI settings** by removing the schema picker
dropdown (no more "Core Schema" vs "Metadata Schema" choice)

## Changes

### Backend
- **Deleted**: `mcp-metadata.controller.ts`, `mcp-metadata.service.ts`
(merged into core)
- **New**: `get-tool-catalog.tool.ts` — browsable, categorized tool
discovery
- **Fixed**: `DatabaseToolProvider.generateDescriptors` — removed guard
that blocked API key access to CRUD tools
- **Fixed**: `ToolContext` type + `ToolRegistryService` — `authContext`
now flows through so API key CRUD execution works end-to-end
- **Updated**: `McpProtocolService` — builds
`ApiKeyWorkspaceAuthContext` for API key requests
- **Updated**: All MCP tool descriptions with explicit step numbering

### Frontend
- **Simplified**: `SettingsAIMCP.tsx` — removed schema selector
dropdown, shows single MCP config

## Test plan
- [x] All 19 MCP unit tests pass (controller + protocol service)
- [x] Server and frontend lint clean
- [x] Server and frontend typecheck pass
- [x] Live-tested on localhost:3000 with API key: `get_tool_catalog`
returns 236 tools including 196 DATABASE_CRUD tools
- [x] Live-tested `execute_tool` with `find_companies` via API key —
returns real data
- [x] Tested MCP connection from Cursor IDE via project-level
`.cursor/mcp.json`

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-20 13:09:54 +01:00
martmull 3bc887e12e Add default relation to standard object on custom object in manifest (#18033)
add default relation fields when creating an object from an application

---------

Co-authored-by: prastoin <paul@twenty.com>
2026-02-20 11:49:06 +01:00
Thomas Trompette d060c843d1 Remove sse feature flag (#18114)
As title
2026-02-20 11:46:03 +01:00
Paul Rastoin 175df59c21 Support Skill in manifest (#18092)
# Introduction
Support skill in manifest, pre-requisite for the twenty standard app
migration
2026-02-20 11:45:42 +01:00
Félix Malfait 6ad581d178 Fix global search for CJK and non-tokenizable text (#18030)
## Summary

Fixes #12962

- Adds a two-pass ILIKE fallback to the global search service
(`search.service.ts`)
- **Fast path**: runs the tsvector query first (uses GIN index,
sub-millisecond)
- **Fallback**: only if tsvector returns fewer results than the limit,
runs an ILIKE query on `searchVector::text` to catch cases where
PostgreSQL's `simple` text search config fails to tokenize (continuous
CJK text, etc.)
- Zero performance impact for the common case (Latin text where tsvector
works)
- Also adds `escapeForIlike` utility to properly escape `%`, `_`, `\` in
user input

### Why tsvector fails for CJK

PostgreSQL's `simple` config treats continuous CJK text as a single
lexeme:
- `to_tsvector('simple', '示例商业线索')` → `'示例商业线索':1`
- Searching `商业:*` only prefix-matches from the start, so it misses `商业`
in the middle

The ILIKE fallback catches these substring matches when the tsvector
path can't.

### What this fixes

- Global search (command menu / sidebar)
- Relation picker (single and multi-object)
- Morph relation picker

All three use `search.service.ts` under the hood.

Co-authored-by: mykh-hailo (original direction in #18021)

## Test plan

- [ ] Search `示例` with records `示例商业线索` and `示例-商业-线索` → both should
appear
- [ ] Search `商业` → both should appear (previously only the hyphenated
one did)
- [ ] Search for Latin text (e.g. `john`) → same performance, results
unchanged
- [ ] Relation picker search with CJK text → results appear
- [ ] Search input with special chars like `%` or `_` → no SQL
injection, results correct


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: mykh-hailo <mykh-hailo@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-20 11:02:09 +01:00
Félix Malfait 726b1373d9 fix: convert metered tier upTo from internal to display credits in listPlans (#18108)
## Summary
- The `listPlans` GraphQL query was returning metered tier `upTo` values
in internal credit units (1000x the display value), causing "Credits by
period" and "Credit Plan" dropdowns to show "50M" instead of "50k"
- Applied the existing `INTERNAL_CREDITS_PER_DISPLAY_CREDIT` (1000)
divisor in `formatBillingDatabasePriceToMeteredPriceDTO`, matching the
conversion already used in `getMeteredProductsUsage` resolver
- Updated frontend mock data to reflect the corrected display-unit
values

## Test plan
- [x] Unit tests pass for `format-database-product-to-graphql-dto.util`
- [x] Unit tests pass for `metered-credit.service` and
`billing-credit-rollover.service`
- [ ] Verify billing page shows correct credit amounts (50k, not 50M)
for "Credits by period" and "Credit Plan"


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
2026-02-20 09:44:11 +01:00
Raphaël Bosi bd03073b6d [FRONT COMPONENTS] Declare command menu items in front components (#18047)
## Description

- Adds support for declaring command menu items directly within
`defineFrontComponent` via an optional command config property
- Introduces a new `CommandMenuItemManifest` type in twenty-shared and
wires it through the manifest build pipeline

## Example Of usage

```tsx
import { defineFrontComponent } from "twenty-sdk";

const TestAction = () => {
  return <div>Test Action</div>;
};

export default defineFrontComponent({
  universalIdentifier: "6c289461-0007-4a62-a99f-69e5c11a4ce7",
  name: "test-action",
  description: "Test Action",
  component: TestAction,
  command: {
    universalIdentifier: "c07df864-495f-46f3-9f5b-9d3ce2589e9b",
    label: "Run My Action",
    icon: "IconBolt",
    isPinned: false,
  },
});

```

## Video QA


https://github.com/user-attachments/assets/f910fc6a-44a9-45d1-87c5-f0ce64bb3878
2026-02-19 15:23:46 +01:00
Weiko 37d9828458 Fix google compose scope not gated by feature flag (#18093)
## Context
New google api scope has been introduced in
https://github.com/twentyhq/twenty/pull/17793 without being gated behind
a feature flag

Microsoft is using pre-existing Mail.ReadWrite scope there is nothing to
gate

## Before
<img width="553" height="445" alt="Screenshot 2026-02-19 at 14 57 58"
src="https://github.com/user-attachments/assets/59a4f76b-d38d-492f-b013-b6cad4091a7f"
/>


## After
<img width="535" height="392" alt="Screenshot 2026-02-19 at 14 58 44"
src="https://github.com/user-attachments/assets/0337bf15-ec30-4549-bb9d-571a982dffd8"
/>
2026-02-19 15:16:54 +01:00
martmull 754de411fe Factorize and add public-assets/*path endpoint (#18080)
as title
2026-02-19 14:00:52 +01:00
github-actions[bot] 7b10202c69 i18n - translations (#18086)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-19 13:17:01 +01:00
github-actions[bot] b33f86fbf5 i18n - translations (#18079)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-19 11:56:21 +01:00
Paul Rastoin 88424611ec Refactor and standardize isSystem field and object (#17992)
# Introduction

## Centralize system field definitions
- Extract a single `PARTIAL_SYSTEM_FLAT_FIELD_METADATAS` constant as the
source of truth for all 8 system fields (`id`, `createdAt`, `updatedAt`,
`deletedAt`, `createdBy`, `updatedBy`, `position`, `searchVector`),
eliminating duplication across custom object and standard app field
builders
- Refactor `buildDefaultFlatFieldMetadatasForCustomObject` to use the
shared constant via a new `buildObjectSystemFlatFieldMetadatas` helper

## Mark system fields as `isSystem: true`
- Fields `id`, `createdAt`, `updatedAt`, `deletedAt`, `createdBy`,
`updatedBy`, `position`, `searchVector` are now properly flagged as
system fields across all standard objects and custom object creation
- Standard app field builders for all ~30 standard objects updated to
set `isSystem: true` on `createdAt`, `updatedAt`, `deletedAt`,
`createdBy`, `updatedBy`
- System-only standard objects (blocklist, calendar channels, message
threads, etc.) now also include `createdBy`, `updatedBy`, `position`,
`searchVector` field definitions that were previously missing

## Validate system fields on object creation
- New transversal validation (`crossEntityTransversalValidation`) runs
after all atomic entity validations in the build orchestrator, ensuring
all 8 system fields are present with correct `type` and `isSystem: true`
when an object is created
- New `buildUniversalFlatObjectFieldByNameAndJoinColumnMaps` utility to
resolve field names to universal identifiers for a given object
- New exception codes: `MISSING_SYSTEM_FIELD` and `INVALID_SYSTEM_FIELD`
on `ObjectMetadataExceptionCode`

## Protect system fields and objects from mutation
- Field validators now block update/delete of `isSystem` fields by
non-system callers (`FIELD_MUTATION_NOT_ALLOWED`)
- Object validators now block update/delete of `isSystem` objects by
non-system callers
- `POSITION` and `TS_VECTOR` field type validators replaced: instead of
rejecting creation outright, they now validate that the field is named
correctly (`position` / `searchVector`) and has `isSystem: true`

## Distinguish `isSystemBuild` from `isCallerTwentyStandardApp`
- New `isCallerTwentyStandardApp` utility checks whether the caller's
`applicationUniversalIdentifier` matches the twenty standard app
- Name-sync logic (`isFlatFieldMetadataNameSyncedWithLabel`,
`areFlatObjectMetadataNamesSyncedWithLabels`) refactored to use
`isCallerTwentyStandardApp` for custom suffix decisions, keeping
`isSystemBuild` for mutation permission checks
- `WorkspaceMigrationBuilderOptions` type updated to include
`applicationUniversalIdentifier`

## Adapt frontend filtering
- New `HIDDEN_SYSTEM_FIELD_NAMES` constant (`id`, `position`,
`searchVector`) and `isHiddenSystemField` utility to only hide truly
internal fields while keeping user-facing system fields (`createdAt`,
`updatedAt`, `deletedAt`, `createdBy`, `updatedBy`) visible in the UI
- ~20 frontend files updated to replace `!field.isSystem` checks with
`!isHiddenSystemField(field)` across record index, settings, data model,
charts, workflows, spreadsheet import, aggregations, and role
permissions

## Add 1.19 upgrade commands
- **`backfill-system-fields-is-system`**: Raw SQL command to set
`isSystem = true` on existing workspace fields matching system field
names, and fix `position` field type from `NUMBER` to `POSITION` for
`favorite`/`favoriteFolder` objects. Includes proper cache invalidation.
- **`add-missing-system-fields-to-standard-objects`**: Codegen'd
workspace migration to create missing `position`, `searchVector`,
`createdBy`, `updatedBy` fields on standard objects that didn't
previously have them. Runs via `WorkspaceMigrationRunnerService` in a
single transaction with idempotency check. **Known limitation**: assumes
all standard objects exist and are valid in the target workspace.

## Add `universalIdentifier` for system fields in standard object
constants
- `standard-object.constant.ts` updated to include `universalIdentifier`
for `createdBy`, `updatedBy`, `position`, and `searchVector` across all
standard objects
- `fieldManifestType.ts` updated to support the new field manifest shape

## System relation
Completely removed and backfilled all `isSystem` relation to be false
false
As we won't require an object to have any relation system fields

## Add integration tests
- New test suite `failing-sync-application-object-system-fields`
covering: missing system fields, wrong field types (`id` as TEXT,
`createdAt` as TEXT, `position` as TEXT), system field deletion
attempts, and system field update attempts
- New test utilities: `buildDefaultObjectManifest` (builds an object
manifest with all 8 system fields) and `setupApplicationForSync`
(centralizes application setup)
- Existing successful sync test updated to verify system fields are
created with correct properties

## Next step
Make the builder scope the compared entity to be the currently built app
+ nor twenty standard app
2026-02-19 10:13:50 +00:00
neo773 04502e5abb Messages Message Folder Association (#17398)
This PR adds Message folder association for message channel messages,
Currently under testing phase, not ready yet.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 23:13:47 +01:00
github-actions[bot] 42108e0611 i18n - translations (#18053)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-18 22:20:32 +01:00
neo773 7de565f70c Prevent SSRF via IMAP/SMTP/CalDAV (#17973)
Prevents leaking of internal services by filtering out private IPs, same
way we do for webhooks
2026-02-18 22:15:10 +01:00
Félix Malfait 67074a7581 Harden server-side input validation and auth defaults (#18018)
## Summary

- **File storage (LocalDriver):** Add realpath resolution and symlink
rejection to `writeFile`, `downloadFile`, and `downloadFolder` — brings
them in line with the existing `readFile` protections. Includes unit
tests.
- **JWT:** Pin signing/verification to HS256 explicitly.
- **Auth:** Revoke active refresh tokens when a user changes their
password.
- **Logic functions:** Validate `handlerName` as a safe JS identifier at
both DTO and runtime level, preventing injection into the generated
runner script.
- **User entity:** Remove `passwordHash` from the GraphQL schema
(`@Field` decorator removed, column stays).
- **Query params:** Use `crypto.randomBytes` instead of `Math.random`
for SQL parameter name generation.
- **Exception filter:** Mirror the request `Origin` header instead of
sending `Access-Control-Allow-Origin: *`.

## Test plan

- [x] `local.driver.spec.ts` — writeFile rejects symlinks, downloadFile
rejects paths outside storage
- [ ] Verify JWT auth flow still works (login, token refresh)
- [ ] Verify password change invalidates existing sessions
- [ ] Verify logic function creation with valid/invalid handler names
- [ ] Verify file upload/download in dev environment


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
2026-02-18 21:41:01 +01:00
Charles Bochet ce1ffa8550 Refactor page layout types (#18042)
## Refactor page layout widget types into shared package and expose from
SDK

### Why

Widget configuration types were defined only on the server, forcing SDK
consumer apps to import from deep internal `twenty-shared/dist` paths —
fragile and breaks on structural changes. Server DTOs also had no
compile-time guarantee they matched the canonical types.

### What changed

- **`twenty-shared`**: Migrated `ChartFilter`, `GridPosition`,
`RatioAggregateConfig` and all 20 widget configuration variants into
`twenty-shared/types`. `PageLayoutWidgetConfiguration` (base, with
`SerializedRelation`) and `PageLayoutWidgetUniversalConfiguration`
(derived via `FormatRecordSerializedRelationProperties`) are now the
single source of truth.
- **`twenty-sdk`**: Re-exported `AggregateOperations`,
`ObjectRecordGroupByDateGranularity`, `PageLayoutTabLayoutMode`, and
`PageLayoutWidgetUniversalConfiguration` so consumer apps import from
`twenty-sdk` directly.
- **`twenty-server`**: All widget DTOs now `implements` their shared
type for compile-time enforcement. Added helpers to convert nested
`fieldMetadataId` ↔ `fieldMetadataUniversalIdentifier` inside chart
filters. Removed redundant local type re-exports.
2026-02-18 20:17:40 +01:00
Charles Bochet c3781e87cc Sync page Layout (#18034)
## Sync page layouts, tabs, and widgets

Adds the ability for SDK applications to synchronize `pageLayout`,
`pageLayoutTab`, and `pageLayoutWidget` entities, following the same
pattern established in #18003 for views and navigation menu items.

### Changes

**`twenty-shared`**
- New `PageLayoutManifest`, `PageLayoutTabManifest`, and
`PageLayoutWidgetManifest` types with a hierarchical structure (page
layout → tabs → widgets)
- Added `pageLayouts: PageLayoutManifest[]` to the `Manifest` type

**`twenty-sdk`**
- New `definePageLayout()` SDK function with validation for
universalIdentifier, name, and nested tabs/widgets
- Wired into the manifest extraction and build pipeline
(`DefinePageLayout` target function, `PageLayouts` entity key)
- Exported from the SDK entry point

**`twenty-server`**
- Added `pageLayout`, `pageLayoutTab`, `pageLayoutWidget` to
`APPLICATION_MANIFEST_METADATA_NAMES`
- New conversion utilities: manifest → universal flat entity for all
three entity types
- Updated `computeApplicationManifestAllUniversalFlatEntity
2026-02-18 17:55:04 +01:00
Etienne 058489b5cc Fixes - Workspace logo migration (#18035)
- Update migration command to handle case where workspace logo is
originated from workspace email and point to twenty-icons.com
- Update same logic for new workspaces
- Add feature-flag for all newly created workspaces
2026-02-18 16:35:48 +01:00
Félix Malfait f4a61f26c0 Replace generic "Unknown error" messages with descriptive error details (#18019)
## Summary

- Replace all generic `"Unknown error"` fallback messages across the
server codebase with messages that include the actual error details
- The most impactful change is in `guard-redirect.service.ts`, which
handles OAuth redirect errors — non-`AuthException` errors (e.g.,
passport state verification failures) now show `"Authentication error:
<actual message>"` instead of the opaque `"Unknown error"`
- Gmail/Google error handler services now include the error message in
the thrown exception instead of discarding it
- Other catch blocks (workflow delay resume, migration runner rollback,
code interpreter, marketplace) now use `String(error)` for non-Error
objects instead of a static fallback

Fixes the class of issues reported in
https://github.com/twentyhq/twenty/issues/17812, where a user saw
"Unknown error" during Google OAuth and had no way to diagnose the root
cause (which turned out to be a session cookie / SSL configuration
issue).

## Test plan

- [ ] Verify OAuth error flows (e.g., Google Auth with misconfigured
callback URL) now display the actual error message on the `/verify` page
instead of "Unknown error"
- [ ] Verify Gmail sync error handling still correctly classifies and
re-throws errors with descriptive messages
- [ ] Verify workflow delay resume failures include the error details in
the workflow run status


Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-18 14:12:47 +00:00
Arun 8e6b267ff3 Allow DATE_TIME IS operand to filter on a whole day (#17529)
Fixes:  https://github.com/twentyhq/core-team-issues/issues/2027

We've replaced the DATE_TIME picker with DATE picker, and changed the
logic to filter for complete day period.



https://github.com/user-attachments/assets/ba7e1078-bab3-4c62-a803-d6a851f14b7d

---------

Co-authored-by: Arun kumar <arunkumar@Aruns-MacBook-Air.local>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2026-02-18 13:44:05 +00:00
github-actions[bot] 9bac8f15d4 i18n - translations (#18029)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-18 13:26:54 +01:00
Raphaël Bosi 2455c859b4 Add SSE for metadata and plug front components (#17998)
Create the necessary tooling to listen to metadata events and plug it to
the front components. Now we have a hot reload like experience when we
edit a component in an app.

## Backend

- Split `EventWithQueryIds` into `ObjectRecordEventWithQueryIds` and
`MetadataEventWithQueryIds`
- Publish metadata event batches to active SSE streams in
`MetadataEventsToDbListener`

## Frontend

- Create a metadata event dispatching pipeline: SSE metadata events are
grouped by metadata name, transformed into
`MetadataOperationBrowserEventDetail` objects, and dispatched as browser
`CustomEvents`
- Add `useListenToMetadataOperationBrowserEvent` hook for consuming
metadata operation events filtered by metadata name and operation type
- Rename `useListenToObjectRecordEventsForQuery` to
`useListenToEventsForQuery`, now accepting both
`RecordGqlOperationSignature` and `MetadataGqlOperationSignature`
- Implement `useOnFrontComponentUpdated` which subscribes to front
component metadata events and updates the Apollo cache when the
component is modified
- Add `builtComponentChecksum` to the front component query and appends
it to the component URL for browser cache invalidation
2026-02-18 11:26:20 +00:00
BOHEUS 5ae1d94f23 Fix connected account permissions (#17598)
Fixes #17411

---------

Co-authored-by: neo773 <neo773@protonmail.com>
Co-authored-by: neo773 <62795688+neo773@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-02-18 01:05:56 +01:00
Abdul Rahman 015ccbf0a7 Navbar customization improvements (#17863)
- Add folder icon editing support
- And other navbar customization fixes/improvements.

---------

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Devessier <baptiste@devessier.fr>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-02-17 19:53:52 +00:00
Charles Bochet c0cc0689d6 Add Client Api generation (#17961)
## Add API client generation to SDK dev mode and refactor orchestrator
into step-based pipeline

### Why

The SDK dev mode lacked typed API client generation, forcing developers
to work without auto-generated GraphQL types when building applications.
Additionally, the orchestrator was a monolithic class that mixed watcher
management, token handling, and sync logic — making it difficult to
extend with new steps like client generation.

### How

- **Refactored the orchestrator** into a step-based pipeline with
dedicated classes: `CheckServer`, `EnsureValidTokens`,
`ResolveApplication`, `BuildManifest`, `UploadFiles`,
`GenerateApiClient`, `SyncApplication`, and `StartWatchers`. Each step
has typed input/output/status, managed by a new `OrchestratorState`
class.
- **Added `GenerateApiClientOrchestratorStep`** that detects
object/field schema changes and regenerates a typed GraphQL client (via
`@genql/cli`) into `node_modules/twenty-sdk/generated` for seamless
imports.
- **Replaced `checkApplicationExist`** with `findOneApplication` on both
server resolver and SDK API service, returning the entity data instead
of a boolean.
- **Added application token pair mutations**
(`generateApplicationToken`, `renewApplicationToken`) to the API
service, with the server now returning `ApplicationTokenPairDTO`
containing both access and refresh tokens.
- **Restructured the dev UI** into `dev/ui/components/` with dedicated
panel, section, and event log components.
- **Simplified `AppDevCommand`** from ~180 lines of watcher management
down to ~40 lines that delegate entirely to the orchestrator.
2026-02-17 18:45:52 +01:00
Félix Malfait 610c0ebc9d Move secure HTTP client IP validation to connection level (#18006)
## Summary
- Refactors SSRF protection from a request-level adapter to
connection-level agents, validating resolved IPs in `createConnection` +
socket `lookup` events
- Sets both `httpAgent` and `httpsAgent` so validation applies
regardless of protocol switches during redirects
- Caps `maxRedirects` to 10 as defense in depth

## Test plan
- [x] All 59 existing + new unit tests pass (agent util, isPrivateIp,
service)
- [x] No linter errors
- [ ] Verify webhook delivery still works with URLs that redirect
- [ ] Verify image upload from external URLs still works (relies on
redirect following)


Made with [Cursor](https://cursor.com)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes core outbound HTTP security behavior and redirect handling,
which could impact webhook/image-fetch flows and connection semantics
despite improved SSRF coverage.
> 
> **Overview**
> Refactors outbound SSRF protection from a custom axios `adapter` to
connection-level `httpAgent`/`httpsAgent` created by new
`createSsrfSafeAgent`, which blocks private IP literals up front and
validates DNS-resolved IPs via the socket `lookup` event.
> 
> When safe mode is enabled, `SecureHttpClientService.getHttpClient` now
always installs both agents and enforces a capped `maxRedirects`
(default `5`), and the old `getSecureAxiosAdapter`
implementation/tests/types are removed. `isPrivateIp` is
tightened/expanded to treat `0.0.0.0/8` as private and avoid
misclassifying bare IPv4 decimals as IPv6.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8261da4ff05ba3bca3318ad647c04faf6603d91a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 16:59:38 +00:00
github-actions[bot] 7c5a13852b i18n - translations (#18007)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-17 17:27:50 +01:00
Etienne 163c1175cb File - Migrate core pictures (workspace and member logo) + workflow attachments (#17924)
- Create a common file-by-id download controller
- Create core picture module with resolver and logic to handle
workspaceLogo and workspaceMemberProfilePicture update
- Create workflow file module (same)
- Data migration
2026-02-17 15:42:50 +00:00
Thomas Trompette b4e924b671 Sync views and navigation items (#18003)
Both objects are necessary to fully enjoy objects within applications

<img width="770" height="311" alt="Capture d’écran 2026-02-17 à 15 19
43"
src="https://github.com/user-attachments/assets/48c51fa4-63f4-45b2-a40a-df73f3aa79be"
/>
2026-02-17 16:32:41 +01:00
Lucas Bordeau 8938dd637f Added relations to SSE events (#17683)
Fixes https://github.com/twentyhq/core-team-issues/issues/2192

This PR implements what is necessary to re-create the query that we
build on the frontend to obtain the returned object record from a
mutation, but on the backend, which was only partially implemented for
REST API.

Usually we want to have relations with only their id and label
identifier field to have lighter payloads.

In the event we only had depth 0 fields, with this PR we have all events
with depth 1 relations.

We have depth 2 for many-to-many cases, like updateOne or updateMany
result :
- Junction tables
- Activity target tables
2026-02-17 13:57:26 +00:00
Thomas des Francs 9477bb3677 Improve AI chat UX (#17974)
## Summary
- update AI chat message typography and list line-height for readability
- apply richer markdown-section styling for headings, spacing,
separators, and inline code
- keep links non-underlined by default with underline on hover, using
accent11 for link color
- preserve previous AI chat table design while keeping other markdown
improvements

## Validation
- yarn eslint
packages/twenty-front/src/modules/ai/components/LazyMarkdownRenderer.tsx
packages/twenty-front/src/modules/ai/components/AIChatMessage.tsx

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-02-17 11:24:33 +01:00
github-actions[bot] aac032e517 i18n - translations (#17986)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-17 11:14:14 +01:00
manstfu e3db73ef46 Change condition for multi-workspace check (#17938)
When deploying with
```
IS_WORKSPACE_CREATION_LIMITED_TO_SERVER_ADMINS=true
IS_MULTIWORKSPACE_ENABLED=true
```
The first workspace can be created successfully. However, any attempt to
create additional workspaces as admin fails with the error: `Workspace
creation is restricted to admins` because `canAccessFullAdminPanel` is
**false**

If these flags are set to false during the initial deployment and
restarting the Docker container, workspace creation works normally.

Problem is caused by `canAccessFullAdminPanel`

---------

Co-authored-by: ehconitin <nitinkoche03@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-02-17 09:29:59 +01:00
Paul Rastoin 2b7b05de2e [OBJECT_MANIFEST_BREAKING_CHANGE] Sync returns workspace migration (#17918)
# Introduction
In this PR we start returning a workspace migration post sync so it can
committed and provided within the tarball

## Universal aggregators utils
Created two utils
### deleteUniversalFlatEntityForeignKeyAggregators
Used when building a universal create action, a newly created actions
should not contain any aggregated foreign key so they won't be codegen
in the workspace migration but also they are overriden at uninversal to
flat transpilation anw

### resetUniversalFlatEntityForeignKeyAggregators
Used before validating a new flat entity creation, some validator will
consume the fk aggregator in order to validate integrity, but of
optimstically provided it can result to errors. To avoid caller
responsability we override them here

## create-field-action refactor
Refactored the universal and flat field create action to be following
the base actions in order to ease typing
Also it was tailored to handle unlimited amount of flat field metadata
in the same actions whereas in the reality we were always only sending
at max 2 ( for relation fields )

Note: relation field has to be provided at the same as if not optimistic
would fail to retrieve circular universal identifiers

## ObjectManifest
Now always expect a `labelIdentifierFieldMetadataUniversalIdentifier`

## Integration test
Created an integration test that creates an app, sync a first manifest
and a second implying update workspace migration action generation
2026-02-16 15:00:24 +01:00
martmull da064d5e88 Support define is tool logic function (#17926)
- supports isTool and timeout settings in defineLogicFunction in apps
and in setting tabs definition
- compute for all toolInputSchema for logic funciton, in settings and in
code steps

<img width="991" height="802" alt="image"
src="https://github.com/user-attachments/assets/05dc1221-cac9-45a3-87b0-3b13161446fd"
/>
2026-02-16 10:43:29 +01:00
Abdullah. b1d3ec665a fix: qs arrayLimit bypass in comma parsing allows denial of service (#17947)
Resolves [Dependabot Alert
454](https://github.com/twentyhq/twenty/security/dependabot/454) and
[Dependabot Alert
455](https://github.com/twentyhq/twenty/security/dependabot/455).

`zapier-platform-cli` leaves in one entry of qs locked at version
`6.5.x`, so the alert might not close automatically. However, the PR
fixes any occurrences in the server itself.
2026-02-15 19:52:23 +00:00
github-actions[bot] 0876197c8d i18n - translations (#17935)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-14 10:54:52 +01:00
neo773 84afbb4d2c feat: add draft email workflow action (#17793)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-02-13 18:20:20 +01:00
github-actions[bot] ebfaff0a53 i18n - translations (#17932)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-13 18:19:38 +01:00
nitin 463ce43442 [FRONT COMPONENT] Add Front component token generation (#17855)
closes https://github.com/twentyhq/core-team-issues/issues/2180


https://github.com/user-attachments/assets/a898455d-eb1c-4d22-b585-785e98fc38a7
2026-02-13 14:18:09 +00:00
github-actions[bot] 975c64bf3d i18n - translations (#17911)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-13 11:20:56 +01:00
Félix Malfait 21c51ec251 Improve AI agent chat, tool display, and workflow agent management (#17876)
## Summary

- **Fix token renewal endpoint**: Use `/metadata` instead of `/graphql`
for token renewal in agent chat, fixing auth issues
- **Improve tool display**: Add `load_skills` support, show formatted
tool names (underscores → spaces) with finish/loading states, display
tool icons during loading, and support custom loading messages from tool
input
- **Refactor workflow agent management**: Replace direct
`AgentRepository` access with `AgentService` for create/delete/find
operations in workflow steps, improving encapsulation and consistency
- **Simplify Apollo client usage**: Remove explicit Apollo client
override in `useGetToolIndex`, add `AgentChatProvider` to
`AppRouterProviders`
- **Fix load-skill tool**: Change parameter type from `string` to `json`
for proper schema parsing
- **Update agent-chat-streaming**: Use `AgentService` for agent
resolution and tool registration instead of direct repository queries

## Test plan

- [ ] Verify AI agent chat works end-to-end (send message, receive
response)
- [ ] Verify tool steps display correctly with icons and proper messages
during loading and after completion
- [ ] Verify workflow AI agent step creation and deletion works
correctly
- [ ] Verify workflow version cloning preserves agent configuration
- [ ] Verify token renewal works when tokens expire during agent chat


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-02-13 09:27:38 +00:00
Etienne 5c2c588885 Files - Migrate attachments in activities (#17808)
As attachment files have migrated from fullPath to file files field,
need to migrate richText logic to fit to new attachment file handling +
data migration
2026-02-13 09:11:23 +00:00
Marie 90a30263ac [Apps] Content + permission tabs for marketplace and installed apps (#17888)
In this PR
- Content tab for marketplace apps and installed apps: complies with
[figma](https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=34845-126856);
addition of field section showing fields added to standard objects;
initiative: arrow opens a sub-table of fields rows. (suggested because
1/ for marketplace apps we cannot redirect to the actual object page in
settings since the object does not exist yet in the workspace 2/ since
we dont have an quick "go back to application page" option, it can be
annoying to be redirected to a different setting page when we just want
to look at the content of the app objects)
- Permission tab for marketplace apps and installed apps
- left to do - settings tab (in another PR)

There are breaking changes but it's behind a feature flag not exposed
(access to marketplace) so not problematic


marketplace apps

https://github.com/user-attachments/assets/4c660101-50fc-47ce-b90a-8d6f17db5e74

installed apps

https://github.com/user-attachments/assets/c9229ee1-e75f-4cad-8766-758b2c5b37b4
2026-02-12 17:38:53 +00:00
Abdullah. 13c2234856 feat: emit metadata events for schema changes with actor context for webhooks (#17622)
## Summary

This PR adds **metadata eventing**: when schema metadata
(objectMetadata, fieldMetadata, view, viewField, etc.) is created,
updated, or deleted, we now emit events that can trigger webhooks and
future audit logs. It also adds **actor context** (`userId`,
`workspaceMemberId`) to those events so subscribers can attribute
changes to a user or API key.

## What changed

### 1. Metadata eventing (first commit)

- **MetadataEventEmitter**  
New service that emits batch events after successful workspace
migrations. Event names follow `metadata.{entity}.{action}` (e.g.
`metadata.objectMetadata.created`, `metadata.fieldMetadata.updated`).
- **MetadataEventsToDbListener**  
Listens for metadata events and enqueues webhook delivery via
`CallWebhookJobsForMetadataJob`.
- **Event types** (twenty-shared)  
`MetadataEventAction`, `MetadataEventBatch`, and record event types for
create/update/delete.
- **WorkspaceMigrationValidateBuildAndRunService**  
Calls the metadata event emitter after running migrations so all
metadata changes (from any module) emit events from a single place.
- **Create events**  
Sourced from the create action payload (`flatEntity` /
`flatFieldMetadatas`) because `fromToAllFlatEntityMaps` does not provide
a before/after diff for creates. Update/delete events still use the
fromToAllFlatEntityMaps comparison.

### 2. Actor context (second commit)

- **MetadataEventEmitter**  
Accepts optional `actorContext` (`userId`, `workspaceMemberId`) and
includes it on emitted batch events.
- **WorkspaceMigrationValidateBuildAndRunService**  
Passes `actorContext` from the request into the metadata event emitter.
- **Metadata resolvers & services**  
All metadata modules resolve `@AuthUser({ allowUndefined: true })` and
`@AuthUserWorkspaceId()` and pass `userId` and `workspaceMemberId`
through to the migration/event pipeline. Both are optional so
API-key–authenticated requests (no user) still emit events without a
user identity.
  
Shared some questions on Discord about the PR.

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: prastoin <paul@twenty.com>
2026-02-12 17:14:25 +00:00