Paul Rastoin 6afc3d33a4 fix: provision INDEX view fields for relations created in the same batch as their object (#23665)
## Context

Fixes twentyhq/core-team-issues#2749: when an app manifest creates an
object and its relation fields in a single sync, the engine-owned INDEX
view ended up with no viewField at all for RELATION / MORPH_RELATION
fields, not even a hidden one. Adding the same relation to a
pre-existing object in a second sync produced a visible viewField.

## Root cause

`fieldIndexViewFieldOnCreate` is the sole owner of caller-field view
fields on the INDEX view (`objectSystemFieldsAndIndexViewOnCreate` only
emits view fields for displayable system fields). Its same-batch branch
gated on `isFlatFieldMetadataDisplayableInDefaultView`, which excludes
RELATION / MORPH_RELATION, so relations were dropped and nothing else
picked them up.

The guard's other exclusions (reserved names like `id`/`deletedAt`,
system-only types TS_VECTOR / POSITION) are unreachable there: side
effect handlers only trigger on caller-authored entities (the engine
reads triggers from the pre-expansion matrix), and the flat field
validators reject those names/types for caller fields. The guard could
only ever drop relations.

## Fix

- Remove the displayability guard from
`buildViewFieldForObjectCreatedInSameBatch`.
- Remove the `displayableOnly` filter from
`computeCallerFlatFieldMetadatasForObject`: every caller field now gets
a view field, and both handlers keep deriving positions from the same
list, so the interleaved layout stays consistent by construction (label
identifier, caller fields in input order with relations, then
displayable system fields).
- Build the view field literal through a single
`buildIndexFlatViewFieldToCreate` helper on all handler branches instead
of `computeFlatViewFieldsToCreate`, whose internal displayability filter
would have dropped relations again. That util keeps its semantics for
its remaining callers (system-field view fields, object creation via
API, committed upgrade commands). Both identifier derivations are the
same deterministic uuid (asserted by an existing twenty-shared spec), so
emitted identifiers are unchanged.
- `isFlatFieldMetadataDisplayableInDefaultView` itself is untouched: the
committed 2-26 upgrade command and the system-field filtering still rely
on its current semantics.

## Tests

- New manifest-sync integration test (first commit, TDD red then green):
a single sync creating two objects and a MANY_TO_ONE / ONE_TO_MANY
relation pair asserts each object's INDEX view has a visible view field
for its relation, plus a control case adding the same relations to
pre-existing objects in a second sync.
- Unit spec: the test that locked in the noop now asserts a visible view
field at the expected position for RELATION and MORPH_RELATION.
- Verified locally: all 62 metadata-side-effect unit tests, the new
integration spec, `successful-sync-application-workspace-migration` (4
snapshots), `relabel-onto-new-field-manifest-sync`,
`create-one-field-metadata-relation`, plus twenty-server typecheck and
lint.
2026-08-03 09:23:12 +00:00
2026-06-11 11:02:28 +02:00

Twenty logo

The #1 Open-Source CRM

Website · Documentation · Roadmap · Discord · Figma

Twenty banner


Why Twenty

Twenty gives technical teams the building blocks for a custom CRM that meets complex business needs and quickly adapts as the business evolves. Twenty is the CRM you build, ship, and version like the rest of your stack.

Learn more about why we built Twenty


Installation

Cloud

The fastest way to get started. Sign up at twenty.com and spin up a workspace in under a minute, with no infrastructure to manage and always up to date.

Build an app

Scaffold a new app with the Twenty CLI:

npx create-twenty-app my-app

Define objects, fields, and views as code:

import { defineObject, FieldType } from 'twenty-sdk/define';

export default defineObject({
  nameSingular: 'deal',
  namePlural: 'deals',
  labelSingular: 'Deal',
  labelPlural: 'Deals',
  fields: [
    { name: 'name', label: 'Name', type: FieldType.TEXT },
    { name: 'amount', label: 'Amount', type: FieldType.CURRENCY },
    { name: 'closeDate', label: 'Close Date', type: FieldType.DATE_TIME },
  ],
});

Then ship it to your workspace:

npx twenty app:publish --private

See the app development guide for objects, views, agents, and logic functions.

Self-hosting

Run Twenty on your own infrastructure with Docker Compose, or contribute locally via the local setup guide.



Everything you need

Twenty gives you the building blocks of a modern CRM (objects, views, workflows, and agents) and lets you extend them as code. Here's a tour of what's in the box.

Want to go deeper? Read the User Guide for product walkthroughs, or the Documentation for developer reference.

Create your apps

Learn more about apps in doc

Stay on top with version control

Learn more about version control in doc

All the tools you need to build anything

Learn more about primitives in doc

Customize your layouts

Learn more about layouts in doc

AI agents and chats

Learn more about AI in doc

Plus all the tools of a good CRM

Learn more about CRM features in doc


Stack

Thanks

Greptile      Sentry      Crowdin

Thanks to these amazing services that we use and recommend for code review (Greptile), catching bugs (Sentry) and translating (Crowdin).

Join the Community

Star the repo · Discord · Feature requests · Releases · X · LinkedIn · Crowdin · Contribute

S
Description
The open alternative to Salesforce, designed for AI.
Readme AGPL-3.0 1.4 GiB
Languages
TypeScript 79.6%
MDX 17.3%
JavaScript 2.7%
Python 0.2%
SCSS 0.1%