Commit Graph

729 Commits

Author SHA1 Message Date
Guillim b83dc3aaff TimelineActivity migration to morph (#15652)
# TimelineActivity migration to morph


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

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

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

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

The plan for this complex migration is as follows :

![plan](https://github.com/user-attachments/assets/51c63ea6-fb0d-40b4-b99d-3e0b35a204e6)
Note: we will need to rename fields in the release 1.12 (there is no
easy way to do all this in one release)
2025-12-11 14:28:26 +01:00
Raphaël Bosi 5af2d37253 [DASHBOARDS] Dashboard duplication (#16291)
## Description

- Created a Dashboard duplication action
- Created a new duplication custom resolver
- Created the service using the v2 of the API
- Created the integration tests following the v2 methodology

## Video QA


https://github.com/user-attachments/assets/e409951a-5946-4da0-91a0-1f7d2ecadb08
2025-12-11 11:15:15 +00:00
Félix Malfait bc57b8ee4e feat(ai): add browsing context and fix tool loading (#16476)
## Summary

- Add `BrowsingContext` type to automatically pass what the user is
currently viewing (recordPage or listView) to the AI chat
- Simplify context architecture: remove toggleable context UI, make it
automatic and invisible to the user
- Fix tool loading: add `unionOf` handling in
`getDatabaseToolsForObject` and fix regex ordering so `find_one_*` tools
are properly registered
- Use plural names for find tools (`find_people` vs `find_one_person`)
for better semantics
- Clean up unused components and states

## Changes

### Frontend
- New `BrowsingContext` type and `useGetBrowsingContext` hook to gather
context from Recoil state
- Simplified `useAgentChat` to use the new browsing context
- Removed toggleable context UI components
(`AgentChatContextRecordPreview`, `SendMessageWithRecordsContextButton`,
etc.)
- Removed `isAgentChatCurrentContextActiveState`

### Backend
- New `BrowsingContextType` for recordPage and listView contexts
- Updated `ChatExecutionService` to build context from browsing context
- Fixed `tool-registry.service.ts`:
  - Added `unionOf` handling in permission config
- Fixed regex ordering (`find_one` before `find`) so tools load
correctly
- Use plural names for search tools (`find_people` instead of
`find_person`)

## Test plan

- [x] Typecheck passes
- [x] Lint passes
- [ ] Test AI chat on record page - should show context in system prompt
- [ ] Test AI chat on list view - should show view name and filters
- [ ] Test `find_one_*` tools now load correctly
- [ ] Test `find_*` tools use plural naming
2025-12-11 10:19:27 +01:00
Weiko 9bd8f94b3a Refactor global datasource part 3 (#16447)
## Context
Following https://github.com/twentyhq/twenty/pull/16399
Now using the new global orm manager everywhere and returning a
GlobalDatasource/WorkspaceDatasource based on a feature flag.
This means we now need to wrap all our ORM calls within
executeInWorkspaceContext callback (at least for now) so the global
datasource can dynamically hydrate its context via the new store (the
global datasource does not store anything related to workspaces as it is
now a unique singleton). If feature flag is off it still uses local data
stored in the workspace datasource.
2025-12-10 17:17:33 +01:00
Weiko 0a11add616 Fix sync role v1 (#16459)
## Context
SyncMetadata for role update was broken when those roles had permission
flags in them.
This PR https://github.com/twentyhq/twenty/issues/16365 introduced a
change in all existing standard roles which probably triggered the
update of faulty roles for the first time. Down the line, some
properties from flat were not omit before querying the DB (in this case
permissionFlagIds does not exist as a column in role table)

The fix is definitely not great, this also probably broke the update of
permissionFlags for existing STANDARD roles but it's not subject to
change (It actually never changed. Again, what has been updated was not
the permission flag but a new boolean introduced 2 days ago which forced
the "UPDATE" path in the sync which was probably never triggered before,
or at least not for roles with permission flags which are "quite" new).
Also we are about to remove this whole code in favor of the new
migration v2
2025-12-10 15:45:04 +01:00
Félix Malfait 5df8fd90c3 feat: simplify AI chat architecture and add record links (#16463)
## Summary

This PR significantly simplifies the AI chat architecture by removing
complex routing/planning mechanisms and introduces clickable record
links in AI responses.

## Changes

### AI Chat Architecture Simplification
- **Removed** the entire `ai-chat-router` module (~850 lines) including:
  - Strategy decider service
  - Plan generator service
  - Complex routing logic
- **Removed** agent execution planning services (~700 lines):
  - `agent-execution.service.ts`
  - `agent-plan-executor.service.ts`
  - `agent-tool-generator.service.ts`
- **Added** centralized `ToolRegistryService` for tool management:
  - Builds searchable tool index (database, action, workflow tools)
  - Provides tool lookup by name
  - Supports agent search for loading expertise
- **Added** `ChatExecutionService` as simple replacement:
  - Includes full tool catalog in system prompt
- Pre-loads common tools (find/create/update for company, person,
opportunity, task, note)
  - Uses `load_tools` mechanism for dynamic tool activation
  - Enables native web search by default

### Record References in AI Responses
- Added `recordReferences` field to tool outputs for create, find, and
update operations
- Implemented `[[record:objectName:recordId:displayName]]` syntax for AI
to reference records
- Created `RecordLink` component that renders clickable chips with
object icons
- Integrated record link parsing into the markdown renderer
- Users can now click directly on created/found records in AI responses

### Workflow Agent Fixes
- Fixed cache invalidation issue when creating agents in workflows
- Added default prompt for workflow-created agents to prevent validation
errors
- Relaxed agent validation to only check properties being updated (not
all required properties)

### Code Quality Improvements
- Extracted `getRecordDisplayName` utility that mirrors frontend's
`getLabelIdentifierFieldValue` logic
- Uses object metadata to determine the correct label identifier field
- Handles `FULL_NAME` composite type for person/workspaceMember objects
- Shared across create, find, and update record services

## Net Impact
- **~1,200 lines deleted** (complex routing/planning code)
- **~500 lines added** (simpler tool registry + record links)
- Significantly reduced code complexity
- Better tool discovery through full catalog in system prompt
- Improved UX with clickable record references

## Testing
- Typecheck passes
- Lint passes
- Manual testing of AI chat with record creation and linking
2025-12-10 15:14:12 +01:00
Raphaël Bosi f48adb5f07 Migrate page layout services (#16443)
Last step of the page layout migration:
- Migrate services
- Write integration tests
2025-12-10 13:49:44 +00:00
Abdul Rahman 1839f8e946 Fix: Persist hide empty groups setting on backend (BREAKING: deploy server first) (#16385)
Closes #13754 and [core team issue
#414](https://github.com/twentyhq/core-team-issues/issues/414)
2025-12-10 19:10:29 +05:30
Paul Rastoin 7b98804ec1 Fix flat field metadata date type (#16445)
# Introduction
Following https://github.com/twentyhq/twenty/pull/16420
2025-12-09 19:53:36 +01:00
Charles Bochet a18203934c Fix flat entity maps date serialization (#16420)
Changes:
- as we store date in redis as serialized, let's make all flatEntity
dates as string. This requires changing FlatEntity types and making sure
that entity are converted to flatEntity and flatEntity to dtos
2025-12-09 16:41:50 +01:00
nitin 7af3da9393 [Dashboards] add ratio aggregate on aggregate chart (#16413)
closes https://github.com/twentyhq/core-team-issues/issues/1960
video QA


https://github.com/user-attachments/assets/e90cee44-5edc-430d-b003-03ab4ea921f7
2025-12-09 15:23:21 +01:00
Paul Rastoin e8d4f11d8e Standard index as code introduction + type refactor (#16426)
# Introduction
Related https://github.com/twentyhq/core-team-issues/issues/1995

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

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

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

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

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

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

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

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

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

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

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

---------

Co-authored-by: prastoin <paul@twenty.com>
2025-12-08 18:05:28 +00:00
Weiko 859004f4fc Refactor global datasource part 2 (#16399)
## Context
Deprecating TwentyORMManager in favor of TwentyORMGlobalManager
(temporarily, as this will simplify the ultimate goal to later replace
all usages with the new TwentyORMGlobalManagerV2 which will have a
similar signature)
This means this PR had to refactor a bit of code to pass down the
workspaceId when not available directly as it is now a requirement,
meaning we also deprecated scopedWorkspaceContextFactory to have a less
obscure way to fetch the workspaceId and have something more
declarative.

Step 3 will be to update TwentyORMGlobalManager to use a featureFlag
toggling and use the new GlobalWorkspaceOrmManager internally using the
new cache service

Step 4 will be to remove the feature flag and pg_pool patch
2025-12-08 17:05:00 +01:00
Raphaël Bosi 5fb7e76005 Migrate page layout to v2 (#16364) 2025-12-08 14:11:24 +00:00
martmull 7f1e69740a 1895 extensibility v1 application tokens (#16365)
First PR to implement application tokens
- add new application role in twenty-server
- move duplicated constants and types to twenty-shared
- will  add role configuration utils into twenty-sdk in another PR
2025-12-08 10:42:46 +01:00
Paul Rastoin 3e57aa14d3 Refactor page layout tab and widgets migration (#16367)
# Introduction
Making columns nullable instead of required + metadata on the fly
migration in typeorm migration that could affect other breaking change
migrations to be run
2025-12-06 10:23:24 +01:00
Félix Malfait 223082a4da refactor(twenty-server): consolidate AI tool provider architecture (#16355)
## Summary

Consolidates the AI tool provider architecture by creating a single
`ToolProviderService` as the entry point for all tool generation. This
removes multiple intermediate services and simplifies the codebase.

## Changes

### New Architecture
- **`ToolProviderService`**: Single service for all tool generation
with:
  - `getTools(spec)` - Get tools by category with permissions
  - `getToolByType(type)` - Get specific tool for workflow execution
  
- **`ToolCategory` enum**: Declarative specification of tool types:
  - `DATABASE_CRUD` - Record CRUD operations
  - `ACTION` - HTTP requests, email sending, article search
  - `WORKFLOW` - Workflow management tools
  - `METADATA` - Object/field metadata tools
  - `NATIVE_MODEL` - Model-specific tools (e.g., web search)

- **`ToolSpecification` type**: Clean API for requesting tools with
permissions

### Removed
- `AiToolsModule` - No longer needed
- `ToolService` - Logic inlined into ToolProviderService
- `ToolAdapterService` - Logic inlined into ToolProviderService
- `ToolRegistryService` - Logic inlined into ToolProviderService

### Updated
- All consumers (agents, chat, MCP, workflows) now use
`ToolProviderService`
- Test files updated accordingly

## Stats
- **547 insertions, 1146 deletions** (net ~600 lines removed)
- 4 services deleted
- 1 module deleted

## Testing
- [x] Typecheck passes
- [x] Lint passes
2025-12-06 06:51:47 +01:00
Paul Rastoin c8f541618d Refactor validate build and run for configuration to be less verbose and more reliable (#16343)
# Introduction
Refactored the api `validateBuildAndRunWorkspaceMigration` to be require
less configuration but to infer required args dynamically depending on
provided metadata maps to compare

## `inferDeletionFromMissingEntities`
Is not dynamically computed avoiding any miss configuration issue and
any missleading devxp

## Maps computation

Making only one call to redis to build both dependency and to be
compared entity maps. It does not matter to avoid passing a about to
compared flat entity maps to could also be a depedency, it's handled
directly in the builder setup optimistic cache logic

Please note that the flat maps used for the service input transpilation
might differ from the one that we will dynamically compute and inject in
the builder. Leading to do 2 redis calls but also race condition prone
validation error
We prefer that this occurs at the builder rather than at the runner
level as the pg instance is not cache and reflect the real state of a
given workspace
In a nutshell, there's a possible race condition between cache
invalidation and computation in both service input transpilers and
builder but we're totally ok with that
2025-12-05 15:41:56 +00:00
Marie 7ce22d5c7e breaking (soft) - Migrate viewGroup.fieldMetadataId -> view.mainGroupByFieldMetadataId (2/3) (#16277)
Should be merged once https://github.com/twentyhq/twenty/pull/16206 has
been released + command run to prod

In this PR
- Remove usage of viewGroup.fieldMetadataId, both in BE and FE states. 
- But we still need to properly populate it until we fully remove
viewGroup.fieldMetadataId from db and ORM entity (upcoming 3rd PR out of
3). fieldMetadataId was removed from CoreViewGroup type and
CreateViewGroupInput and is determined BE-side based on the associated
view's mainGroupByFieldMetadataId. **I expect this means a downtime on
viewGroup creation, until both FE and BE are deployed and cache is
flushed.** This seems acceptable to me as it only regards viewGroup
creation.
    - this information is replaced by view.mainGroupByFieldMetadataID
- Handle view group creation, update and deletion in the BE as a
side-effect of a view creation, update or deletion. Optimistic effects
are still used
- Add validation at view creation or update regarding
mainGroupByFieldMetadata

Left to do in 3rd PR
- Remove viewGroup.fieldMetadataId from db and ORM entity
- Restore feature allowing to update an existing grouped view's group by
field (already OK on BE side but need to rebuild FE optimistic)
2025-12-05 14:00:03 +00:00
Raphaël Bosi 077be7644c Migrate page layout widget to v2 of the API (#16323) 2025-12-05 13:04:06 +00:00
Félix Malfait 2803292521 feat: add Metadata Builder agent for data model management (#16350)
## Summary

This PR adds a new **Metadata Builder** AI agent that specializes in
managing the workspace data model (creating objects, adding fields,
etc.).

## Changes

### New Files
- `data-model-manager-role.ts` - New standard role with `DATA_MODEL`
permission flag
- `metadata-builder-agent.ts` - New standard agent for data model
management

### Modified Files
- **ChatToolsProviderService**: Refactored to consolidate all
permission-based tools into a single `getChatTools()` method. Now
injects both workflow tools and metadata tools based on permissions.
- **AgentChatRoutingService**: Updated to use the new consolidated
`getChatTools()` method
- **AiChatModule**: Added imports for `ObjectMetadataModule` and
`FieldMetadataModule`
- **Router system prompt**: Added metadata-builder agent selection rules
with clear distinction between schema operations vs data operations
- **Metadata tools factories**: Improved error messages to show detailed
validation errors instead of generic messages

### Refactoring
- Renamed `index.ts` files to `standard-agent-definitions.ts` and
`standard-role-definitions.ts` to follow naming conventions
- Renamed exports from `standardAgentDefinitions` to
`STANDARD_AGENT_DEFINITIONS` (SCREAMING_SNAKE_CASE)

## Key Features

1. **Metadata Builder Agent** can:
   - Create new custom objects
   - Add fields to existing objects
   - Update object and field properties
   - Create relations between objects

2. **Permission-based tool injection**: Tools are automatically injected
based on the `DATA_MODEL` permission flag

3. **Improved routing**: The router now correctly distinguishes between:
   - "Create an object called Project" → metadata-builder (schema)
   - "Create a company called Acme" → data-manipulator (data)

4. **Better error messages**: Validation errors now show detailed
messages like:
   ```
   Validation errors:
   [objectMetadata] Name must be in camelCase format
   [objectMetadata] Label is required
   ```
2025-12-04 23:26:29 +01:00
Félix Malfait 34d7d82099 refactor(mcp): call metadata services directly instead of REST layer (#16349)
## Summary

Refactors MCP metadata tools to call underlying services directly
instead of going through the REST layer. This makes MCP a pure
presentation layer.

### Changes

**Created:**
-
`packages/twenty-server/src/engine/metadata-modules/metadata-tools/metadata-tools.module.ts`
- Module that exports MetadataToolsFactory
-
`packages/twenty-server/src/engine/metadata-modules/metadata-tools/services/metadata-tools.factory.ts`
- Factory that generates 8 metadata tools using Zod schemas:
- `get-object-metadata`, `create-object-metadata`,
`update-object-metadata`, `delete-object-metadata`
- `get-field-metadata`, `create-field-metadata`,
`update-field-metadata`, `delete-field-metadata`

**Modified:**
-
`packages/twenty-server/src/engine/api/mcp/services/mcp-metadata.service.ts`
- Uses new factory instead of REST-based services
- `packages/twenty-server/src/engine/api/mcp/mcp.module.ts` - Imports
MetadataToolsModule, removes old service imports

**Deleted:**
-
`packages/twenty-server/src/engine/api/mcp/services/tools/create.tools.service.ts`
-
`packages/twenty-server/src/engine/api/mcp/services/tools/update.tools.service.ts`
-
`packages/twenty-server/src/engine/api/mcp/services/tools/delete.tools.service.ts`
-
`packages/twenty-server/src/engine/api/mcp/services/tools/get.tools.service.ts`
-
`packages/twenty-server/src/engine/api/mcp/services/tools/mcp-metadata-tools.service.ts`

### Architecture Improvement

**Before:**
```
MCP Tool → MetadataQueryBuilderFactory → RestApiService → GraphQL API → Service
```

**After:**
```
MCP Tool → Service (ObjectMetadataService / FieldMetadataService)
```

This follows the pattern established by `direct-record-tools.factory.ts`
and workflow tools.
2025-12-04 22:21:16 +01:00
Félix Malfait 9cecbaebc3 refactor(workflow-tools): reorganize to one file per tool with co-located schemas (#16313)
## Summary

Reorganizes workflow tools to improve maintainability and
discoverability by having one file per tool with co-located input
schemas.

## Changes

- Create individual tool files in `tools/` directory (11 files)
- Co-locate input schemas with their tool implementations
- Add shared types file for dependencies and context
- Simplify workspace service to aggregate tool factories
- Remove centralized `schemas/` directory

## New Structure

```
workflow-tools/
├── services/
│   └── workflow-tool.workspace-service.ts
├── tools/
│   ├── activate-workflow-version.tool.ts
│   ├── compute-step-output-schema.tool.ts
│   ├── create-complete-workflow.tool.ts
│   ├── create-draft-from-workflow-version.tool.ts
│   ├── create-workflow-version-edge.tool.ts
│   ├── create-workflow-version-step.tool.ts
│   ├── deactivate-workflow-version.tool.ts
│   ├── delete-workflow-version-edge.tool.ts
│   ├── delete-workflow-version-step.tool.ts
│   ├── update-workflow-version-positions.tool.ts
│   └── update-workflow-version-step.tool.ts
├── types/
│   └── workflow-tool-dependencies.type.ts
└── workflow-tools.module.ts
```

## Benefits

- **Co-location**: Schema and tool logic are in the same file
- **Single responsibility**: Each file handles one tool
- **Easier maintenance**: Changes to a tool only touch one file
- **Better discoverability**: File names match tool names
2025-12-04 21:06:49 +01:00
Weiko 1991ee850e Fix seeding perf + batch role targets creation (#16337) 2025-12-04 20:29:48 +01:00
Paul Rastoin 28cdb02fbb Twenty standard application Objects and fields as allFlatEntityMaps ID non-agnostic (#16298)
# Introduction

Related to https://github.com/twentyhq/core-team-issues/issues/1995
This PR introduces the basis of the `twentyStandard` application as code
on demand, it's highly tied to `ids` where it will becomes workspace
agnostic following the builder and runner `universalIdentifier` refactor
later.

The goal here to allow computing the `allFlatEntityMaps` `to` of the
`twentyStandard` application on a empty workspace ( workspace creation
). Allowing installing the twenty standard app through a workspace
migration instead of passing by the sync metadata

Nothing done will be run in production for the moment if it's not the
small validation refactor we've introduced

Please note that everything introduced here will be replaced at some
point by a twenty app instance when the twenty sdk is mature enough to
handle of the edge cases we need here

## How we've proceeded
We've been iterating over every workspace entity both objects and their
fields, and transpiled them to flatEntity.
Being sure we migrate the defaultValue, settings and so on accordingly.
We've also compute all the ids in prior of the whole entities
computation so we don't face any hoisting issue.

## Current state
At the moment only handling all of the 29 standard objects and their
fields
Settings a unique universalIdentifier for all of them

Will come views, agent role targets and so on later

## `workspace:compute-twenty-standard-migration` command
This command allow generating a workspace migration that will result in
installing the twenty standard app in an empty workspace
It's temporary and aims to allow debugging for the moment we might not
keep it in the future as it is right now
It contains debug writeFileSync which is expected no worries greptile

## `LabelFieldMetadataIdentifierId`
Small refactor allowing defining the label identifier field metadata id
of a uuid field metadata type for system object, as some of our standard
object don't have a name field and don't aim to
Also please note that we might remove this build options later in the
sake of the currently installed universal identifier application that we
could compare with the deterministic twenty standard one

## `runFlatFieldMetadataValidators`
Deprecated this pattern which was redundant and not v2 friendly pattern

## Current errors that will address in upcoming PR
Current standard objects and fields metadata does not pass the
validation that we have in place, as historically the sync metadata
would directly consume the repositories and would just ignore the
validation. This is about to change.
Will handle the below errors in dedicated PRs as they will required
upgrade commands in order to migrate the data, or will handle that from
the sync metadata instead still to be determined but nothing critical
here

- camel case field metadata name
- options label invalid format

```json
{
  "status": "fail",
  "report": {
    "fieldMetadata": [
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Name should be in camelCase",
            "userFriendlyMessage": {
              "id": "P+jdmX",
              "message": "Name should be in camelCase"
            },
            "value": "iCalUID"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "68dd83cd-92c8-4233-bb28-47939bab6124",
          "name": "iCalUID",
          "objectMetadataId": "11c16ab6-9176-439e-a2db-a12c5a58a524"
        },
        "type": "create_field"
      },
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"email\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "email"
              }
            },
            "value": "email"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"sms\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "sms"
              }
            },
            "value": "sms"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "e3caaf2a-e07d-4146-8dfc-9eef904e82c9",
          "name": "type",
          "objectMetadataId": "4b777de5-4c7b-4af4-9b92-655c0f87512b"
        },
        "type": "create_field"
      },
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"incoming\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "incoming"
              }
            },
            "value": "incoming"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"outgoing\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "outgoing"
              }
            },
            "value": "outgoing"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "d96233a4-93be-45ea-9548-3b50f3c700cf",
          "name": "direction",
          "objectMetadataId": "480a648a-d2e5-482a-992f-ef053e1b4bb0"
        },
        "type": "create_field"
      },
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"from\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "from"
              }
            },
            "value": "from"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"to\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "to"
              }
            },
            "value": "to"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"cc\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "cc"
              }
            },
            "value": "cc"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Value must be in UPPER_CASE and follow snake_case \"bcc\"",
            "userFriendlyMessage": {
              "id": "UBPzFQ",
              "message": "Value must be in UPPER_CASE and follow snake_case \"{sanitizedValue}\"",
              "values": {
                "sanitizedValue": "bcc"
              }
            },
            "value": "bcc"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "961c598e-67c3-452d-8bb2-b92c0bc64404",
          "name": "role",
          "objectMetadataId": "8af8a13c-ff97-4cd3-b70d-52a7dc2924b4"
        },
        "type": "create_field"
      },
      {
        "status": "fail",
        "errors": [
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Label must not contain a comma",
            "userFriendlyMessage": {
              "id": "k731jp",
              "message": "Label must not contain a comma"
            },
            "value": "Commas and dot (1,234.56)"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Label must not contain a comma",
            "userFriendlyMessage": {
              "id": "k731jp",
              "message": "Label must not contain a comma"
            },
            "value": "Spaces and comma (1 234,56)"
          },
          {
            "code": "INVALID_FIELD_INPUT",
            "message": "Label must not contain a comma",
            "userFriendlyMessage": {
              "id": "k731jp",
              "message": "Label must not contain a comma"
            },
            "value": "Dots and comma (1.234,56)"
          }
        ],
        "flatEntityMinimalInformation": {
          "id": "7fa20caf-2597-42e3-84e5-15a91b125b9b",
          "name": "numberFormat",
          "objectMetadataId": "a6974302-9e72-461c-aa09-9390f4ff16fc"
        },
        "type": "create_field"
      }
    ],
    "objectMetadata": [],
    "view": [],
    "viewField": [],
    "viewGroup": [],
    "index": [],
    "serverlessFunction": [],
    "cronTrigger": [],
    "databaseEventTrigger": [],
    "routeTrigger": [],
    "viewFilter": [],
    "role": [],
    "roleTarget": [],
    "agent": []
  }
}
```
2025-12-04 17:39:12 +01:00
Paul Rastoin b2d785de4b Page layout tab v2 (#16319)
# Introduction
Migrating `pageLayoutTab` to the v2 engine
- Types and constants
- Builder and validate
- Runner

Introduced a new `StrictSyncableEntity` that enforces that
`universalIdentifier` and `applicationId` are defined
As these entities are brand new we could enforce this rule already
This still requires a migration command to associate the existing
entities to custom workspace application instance and define
universalIdentifier

Handled retro-comp of the migration through a migration as upgrade
command fallback

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
2025-12-04 17:37:16 +01:00
martmull 5e8fbc7c5c 1825 extensibility v1 see serverless logs using subscriptions in twnty cli or settings serverkess section (#16321)
- Adds a log section to settings serverless functions test tab

<img width="1303" height="827" alt="image"
src="https://github.com/user-attachments/assets/2ce70558-91bc-4cfc-aced-42ac9e0226bf"
/>

- Adds a new subscription endpoint to graphql api
`serverlessFunctionLogs` that that emit function logs

- Adds a new command `twenty app logs` to `twenty-sdk` to watch logs in
terminal

<img width="1109" height="182" alt="image"
src="https://github.com/user-attachments/assets/2e874060-e99d-4978-ab9c-c91e52cb7478"
/>


<img width="1061" height="176" alt="image"
src="https://github.com/user-attachments/assets/1f533e32-7435-4d7b-89c6-d1154816a8ab"
/>

- add new version for create-twenty-app and twenty-sdk `0.1.3`
2025-12-04 16:40:58 +01:00
Weiko c3deb96c8d Fix metadata cache being recomputed twice (#16331)
## Context
Call to incrementMetadataVersion is only done in sync-metadata (to be
deprecated) and migration runner v2. They both already invalidate the
cache so we were doing it twice which is quite heavy with all the
object/field/view/etc maps in it.
2025-12-04 16:01:24 +01:00
Weiko 3d95d6ca00 Add local only cache to cache service and cache typeorm entity metadata (#16287)
## Problem

buildEntityMetadatas in GlobalWorkspaceOrmManager is computationally
expensive and was running on every executeInWorkspaceContext call. This
method uses
TypeORM's EntitySchemaTransformer and EntityMetadataBuilder to build
metadata for all workspace entities (30-50+ objects with many fields
each).

The resulting EntityMetadata[] is not serialisable which means it cannot
be cached in Redis because they contain:
- Circular references
- Functions/methods
- References to the DataSource instance

## Solution

Extended the workspace cache system to support local-only caching, then
created a cache provider for entityMetadatas.

## Implementation details
Updated @WorkspaceCache decorator (workspace-cache.decorator.ts)
- Added localOnly?: boolean option to skip Redis storage for
non-serializable data
Created WorkspaceEntityMetadatasCacheService
- Computes entity metadatas from DB to avoid race condition, this is
acceptable
Simplified GlobalWorkspaceOrmManager
- Now fetches entityMetadatas from cache instead of rebuilding on every
call
Updated Workspace migration runner - the only entry point where metadata
can change
- Now invalidate the new 'entityMetadata' local cache when
shouldIncrementMetadataGraphqlSchemaVersion is true (== field/object
mutations)
2025-12-03 19:50:40 +01:00
Paul Rastoin a829ae62e2 Remove IS_WORKSPACE_MIGRATION_V2_ENABLED feature flag (#16280)
# Introduction
closes https://github.com/twentyhq/core-team-issues/issues/1911
2025-12-03 15:47:08 +00:00
Félix Malfait 578aa9d5ca Fix view disappearing when switching from WORKSPACE to UNLISTED visibility (#16289)
## Description

When switching a view's visibility from WORKSPACE to UNLISTED, the code
in `view-v2.service.ts` correctly sets `createdByUserWorkspaceId` to the
current user (to prevent the view from disappearing). However, this
property was not included in `FLAT_VIEW_EDITABLE_PROPERTIES`, which
meant:

1. The comparison logic didn't detect the change
2. No update action was created for the property  
3. The value was never persisted to the database
4. The view disappeared because it became UNLISTED with no owner

This fix adds `createdByUserWorkspaceId` to the editable properties so
the change is properly detected and persisted.

Might fix https://github.com/twentyhq/twenty/issues/15955
2025-12-03 15:56:31 +01:00
Paul Rastoin 59672e3e34 Migrate agent v2 (#16214)
# Introduction
Closes https://github.com/twentyhq/core-team-issues/issues/1980

In this PR we migrate the agent from v1 to v2.

## New FlatRoleTargetByAgentIdMaps
Derivated the `flatRoleTargetMaps` to be building a
`flatRoleTargetByAgentIdMaps` to ease retrieving a roleId to associate
to an agent

## Coverage
Added strong coverage on both failing and successful CRU agents
operations

---------

Co-authored-by: Weiko <corentin@twenty.com>
2025-12-03 11:51:19 +01:00
Abdul Rahman f248b3f7f4 refactor: move agent evaluation to background jobs for non-blocking execution (#16234) 2025-12-03 05:55:47 +01:00
Marie 77409b6eb2 [Requires "warm" cache flush (no immediate downtime before flush)] Migrate viewGroup.fieldMetadataId -> view.mainGroupByFieldMetadataId (1/3) (#16206)
In this PR (1/3)
- introduce view.mainGroupByFieldMetadataId as the new reference
determining which fieldMetadataId is used in a grouped view, in order to
deprecate viewGroup.fieldMetadataId which creates inconsistencies.
view.mainGroupByFieldMetadataId is now filled at every view creation,
though not in use yet.
- Introduce a command to backfill view.mainGroupByFieldMetadataId for
existing views + delete all viewGroup.fieldMetadataId with a
fieldMetadataId that is not view.mainGroupByFieldMetadataId. (It should
concern 37 active workspaces)
- Temporarily disable the option to change a grouped view's
fieldMetadataId as for now it creates inconsistencies. This feature can
be reintroduced when we have done the full migration.

In a next PR
- (2/3) use view.mainGroupByFieldMetadataId instead of
viewGroup.fieldMetadataId. In FE we may keep viewGroup.fieldMetadataId
as a state (TBD). View groups will now be created / deleted as a side
effect of view's mainGroupByFieldMetadataId update.
- (3/3) remove viewGroup.fieldMetadataId

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-12-02 16:31:07 +01:00
Weiko 13e283fc3a Rename roleTargets -> roleTarget (#16247) 2025-12-02 14:39:54 +01:00
Paul Rastoin eedb163131 Field metadata and object metadata v1 relicas (#16230)
# Introduction

Related https://github.com/twentyhq/core-team-issues/issues/1911

Nearly done with all functional v1 implemen removal
Will remain dead code methods that I will detect using knip
2025-12-02 12:06:28 +01:00
Etienne 68c429a54a Null equivalence - remove feature flag (#16222) 2025-12-01 19:06:24 +01:00
Etienne 5e00893c37 Null equivalence - Empty string default value cleaning (#16217)
- on name standard field on custom object (field metadata + db)
- on text standard fields on standard object (db only)
2025-12-01 17:10:45 +01:00
Weiko 1eb2e44058 Refactor workspace cache service (#16208)
## Context
We've recently introduced a new workspace cache service which now acts
as a cache access and local storage for all workspace related data,
deprecating the individual specific services.
- Better performance through multiple caching/fetching strategies
- Consistent data access patterns across the codebase
- Reduced redis queries through MGET/MSET/PIPELINE with multiple cache
keys
2025-12-01 17:08:21 +01:00
Abdullah. ee08060798 Improve deactivated objects & fields behaviors. (#16090)
Closes [1918](https://github.com/twentyhq/core-team-issues/issues/1918).

- For the first point in the issue, we just show the deactivated entries
along with the deactivated text.

---

- For the second point, we show a banner and control the
enabled/disabled state of save button depending on whether we're
allowing the user to create table with the typed name.
- For example, we do not want to allow the user to create a table with
reserved name, so we disable the save button without showing a banner.
- Similarly, we do not want the user to create a table with a name that
already exists in the database. In this case, we show a banner and we
also disable the save button.
- Finally, we do not want to allow the user to create a table where
singular and plural name are the same. Therefore, we disable the save
button for names like `works`.

---

- For the third point, if we add the delete button, it logically means
that we allow the user to delete a custom object/field even it has not
been deactivated yet, so did that.
- Upon deleting the object/field, if we wait for the metadata to refetch
before we navigate, this is what we see because the path does not exist
any longer after deletion and we're waiting for refetch on the path
until we navigate away.


https://github.com/user-attachments/assets/dbe0569c-db88-4285-851f-22551b1ca81e

- To avoid this page from appearing, I replaced awaiting refetch to not
awaiting refetch and redirecting while the refetch happens in the
background.
- Therefore, when we delete something, there is a slight delay for when
it is actually cleared out from the list, but the Not Found view does
not appear on the screen.


https://github.com/user-attachments/assets/47f49579-ce51-4d6a-b857-72046247bb4b

- I tried optimistically removing the object/field from the metadata,
but it leads to some issues (crashes the app) and I have not been able
to find a solution for it yet.
- Therefore, instead of getting stuck at perfection and blocking myself,
I stopped getting into the issue further and created this PR by ensuring
that the desired functionality works.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Display deactivated objects/fields by default, add delete actions with
confirmation, and unify metadata name computation (auto-suffix reserved
keywords) across front/back with conflict checks in object creation.
> 
> - **Frontend (Settings/Data Model)**:
> - **Visibility/UX**: Show `Deactivated` labels for objects/fields;
filters default to include inactive (`showDeactivated`/`showInactive`
true); replace field action dropdown with chevron link.
> - **Delete flows**: Add delete buttons for custom objects/fields with
confirmation modals and background refetch to avoid Not Found flashes.
> - **Creation/Edit validation**: Add name conflict detection banner in
`SettingsDataModelObjectAboutForm` and disable Save on conflicts;
simplify `metadataLabelSchema` to use computed name; form fields
validate on change and sync API names.
> - **Shared (twenty-shared/metadata)**:
> - Add `computeMetadataNameFromLabel` util (slugify+camelCase) and
`RESERVED_METADATA_NAME_KEYWORDS`; auto-append `Custom` to reserved
names; export constants/utilities.
> - **Backend**:
> - Migrate to shared `computeMetadataNameFromLabel`; update validators
to use shared reserved keywords with new messages; allow deletion of
active custom fields/objects (keep standard guards); adjust
services/decorators accordingly.
> - **Tests/Stories**:
> - Update unit/integration snapshots for new reserved-name messages and
behaviors; add missing i18n/router decorators in stories.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5b126155606f6dbc8f7f91e2192cffb7bd2ebd2c. 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: Félix Malfait <felix@twenty.com>
2025-12-01 15:04:36 +00:00
Paul Rastoin 9f62188ba6 Field and object metadata naming does not refer to v2 (#16187)
Related https://github.com/twentyhq/core-team-issues/issues/1911
2025-11-28 18:06:44 +01:00
Paul Rastoin ea3c5d2d45 Migrate role and role target to v2 (#16009)
# Introduction
close https://github.com/twentyhq/core-team-issues/issues/1930
close https://github.com/twentyhq/core-team-issues/issues/1929
Migrating role and roleTarget entities to the v2 core engine, allowing
v2 caching leverage and allow migrating agent to v2 that needs role
target in prior
After agent we should be able to pass twenty standard app totally though
workspace migration

## Role target assignation
Please note that role target have 3 creation entrypoints:
- Agent
- User workspace
- ApiKey

Refactored all 3 of them to pass through a new role-target.service.ts
that consumes the v2 under the hood.

---------

Co-authored-by: Weiko <corentin@twenty.com>
2025-11-28 17:06:11 +00:00
Paul Rastoin 5016c25daa Remove viewGroup v1 implem (#16178)
# Introduction
Removing v1 implementation of view groups and both view group and view
field relicas front fetchers

Related https://github.com/twentyhq/core-team-issues/issues/1911
2025-11-28 16:36:28 +01:00
Charles Bochet 9387680020 Rollback standard id removal on relation object creation (#16177) 2025-11-28 15:11:45 +01:00
Charles Bochet eb362c6d5f Update workspace entities to make all TEXT nullable (#16144)
Follow up on #15926

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
Co-authored-by: guillim <guigloo@msn.com>
2025-11-28 10:50:38 +01:00
Weiko 9620a4b0ba Optimize EntityMetadata caching in GlobalWorkspaceDataSource (#16146)
## Context
EntityMetadata was being rebuilt from scratch on every
findMetadata()/getMetadata() call (~20 times per request). This involved
running EntitySchemaTransformer.transform() and
EntityMetadataBuilder.build() repeatedly, causing unnecessary CPU
overhead.

## Implementation
Cache entityMetadatas in ORMWorkspaceContext: Build EntityMetadata once
during workspace context initialization instead of on every metadata
lookup
Remove redundant entitySchemas caching: Since flatMetadata is already
cached, the additional Redis cache for entitySchemaOptions was
unnecessary overhead
Remove WorkspaceEntitiesStorage: Replaced with direct lookup from
FlatObjectMetadataMap
Simplify getObjectMetadataFromEntityTarget: Now only accepts string
targets, using flat metadata maps directly

Also:
Removed unused injections in some services
2025-11-28 10:09:52 +01:00
Paul Rastoin e53e0d266d Remove view filter v1 implem (#16154)
# Introduction
Removing view filter v1 implem 

Related https://github.com/twentyhq/core-team-issues/issues/1911
2025-11-28 00:17:17 +01:00