Migrate Company and Person standard fields in preparation for the enrichment app (#21171)
# Migrate Company and Person standard fields in preparation for the
enrichment app
## Why
Our standard `Person`/`Company` objects accumulated fields that aren't
generic to every
business, while missing a more universal revenue field that essentially
every CRM ships.
This PR makes the **Standard application** hold a tighter, more
universal set of fields,
and sets the stage for a follow-up PR that introduces a **People Data
Labs enrichment app**
to populate them.
## What changes
### Standard fields
**Demoted (Standard → Workspace Custom application)** — not generic
enough to ship as standard:
| Object | Field | Type |
| ------- | ------------------------------ | -------- |
| Company | annualRecurringRevenue (ARR) | CURRENCY |
| Company | employees | NUMBER |
| Company | idealCustomerProfile (ICP) | BOOLEAN |
| Company | xLink (X/Twitter) | LINKS |
| Person | xLink (X/Twitter) | LINKS |
| Person | city | TEXT |
**Added (new generic Standard field)** — present in
Salesforce/HubSpot/Zoho, PDL-populatable:
| Object | Field | Type |
| ------- | ------------- |
-------------------------------------------------------- |
| Company | annualRevenue | CURRENCY (generic total revenue; replaces
the niche ARR) |
### Behavior by workspace
* **New workspaces:** demoted fields are gone; `annualRevenue` is
**active**.
* **Existing workspaces:** demoted fields are **preserved as active
custom fields, data intact**;
`annualRevenue` is created **inactive (opt-in)** with its column ready,
so a later activation
is a metadata-only toggle.
### Upgrade commands (v2.9)
Three idempotent, per-workspace commands, run in timestamp order:
1. **`upgrade:2-9:move-demoted-standard-fields-to-custom-application`**
(1799000040000) —
re-owns the 6 demoted fields to the workspace custom application
(`isCustom = true`,
new `applicationId` + fresh `universalIdentifier`), keeping their data
and active state.
2. **`upgrade:2-9:rename-conflicting-custom-fields`** (1799000045000) —
if a workspace already
has a *custom* field named `annualRevenue`, renames it to
`annualRevenueCustom`
(data preserved via column rename) so the standard field can be added.
Skips non-custom matches.
3. **`upgrade:2-9:add-inactive-generic-standard-fields`**
(1799000050000) — creates
`Company.annualRevenue` on existing workspaces as inactive, guarded to
skip workspaces
missing the target object or where the name is still taken.
**Failure model:** the workspace iterator isolates failures per
workspace (one workspace failing
never affects others); within a workspace the runner records per-command
status and resumes on the
next run, and every command is idempotent, so partial runs self-heal.
### Supporting changes
* **Field-option color palette:** widened the `TagColor` union
(`twenty-shared` `FieldMetadataOptions`
+ the field-metadata `options.input` DTO) from 10 colors to the full
theme palette, benefiting any
future SELECT/MULTI_SELECT field.
* **Dev seeder:**
* The default "Annual Recurring Revenue" dashboard widget now points at
the generic
`annualRevenue` field (renamed to "Annual Revenue").
* Removed the "Companies by Size (Stacked by City)" widget (relied on
the demoted `employees`).
* `employees` is dropped from company data seeds and re-added as a
**custom** field seed, so dev
workspaces still get an `employees` column matching the demoted
behavior.
### Cleanup
Front-end record types (`Company.ts`/`Person.ts`), the
`getDisplayNameFromParticipant` test mock,
metadata integration specs, the Zapier `crud_record` test, and the
regenerated
`get-standard-object-metadata-related-entity-ids` snapshot.
## ⚠️ Breaking change (intentional)
Removes standard fields `Company.annualRecurringRevenue`,
`Company.employees`,
`Company.idealCustomerProfile`, `Company.xLink`, `Person.xLink`, and
`Person.city` from the core
GraphQL schema (replaced by `Company.annualRevenue`).
This is why the breaking-changes check reports a large number of
removals — `graphql-inspector`
flags any removed object field plus its derived
aggregate/order-by/filter/update types.
**Mitigation:** the
`upgrade:2-9:move-demoted-standard-fields-to-custom-application` command
re-owns these fields as custom fields per workspace, preserving their
name and data, so existing
tenants keep working. New workspaces won't have them.
This commit is contained in:
-6
@@ -24,7 +24,6 @@ export const prefillCompanies = async (
|
||||
'addressAddressState',
|
||||
'addressAddressPostcode',
|
||||
'addressAddressCountry',
|
||||
'employees',
|
||||
'position',
|
||||
'createdBySource',
|
||||
'createdByWorkspaceMemberId',
|
||||
@@ -45,7 +44,6 @@ export const prefillCompanies = async (
|
||||
addressAddressState: 'CA',
|
||||
addressAddressPostcode: '94103',
|
||||
addressAddressCountry: 'United States',
|
||||
employees: 5000,
|
||||
position: 1,
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
@@ -64,7 +62,6 @@ export const prefillCompanies = async (
|
||||
addressAddressState: 'CA',
|
||||
addressAddressPostcode: '94104',
|
||||
addressAddressCountry: 'United States',
|
||||
employees: 1100,
|
||||
position: 2,
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
@@ -83,7 +80,6 @@ export const prefillCompanies = async (
|
||||
addressAddressState: null,
|
||||
addressAddressPostcode: null,
|
||||
addressAddressCountry: 'Ireland',
|
||||
employees: 8000,
|
||||
position: 3,
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
@@ -102,7 +98,6 @@ export const prefillCompanies = async (
|
||||
addressAddressState: null,
|
||||
addressAddressPostcode: '94102',
|
||||
addressAddressCountry: 'United States',
|
||||
employees: 800,
|
||||
position: 4,
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
@@ -121,7 +116,6 @@ export const prefillCompanies = async (
|
||||
addressAddressState: 'CA',
|
||||
addressAddressPostcode: '94110',
|
||||
addressAddressCountry: 'United States',
|
||||
employees: 400,
|
||||
position: 5,
|
||||
createdBySource: FieldActorSource.SYSTEM,
|
||||
createdByWorkspaceMemberId: null,
|
||||
|
||||
-6
@@ -26,7 +26,6 @@ export const prefillPeople = async (
|
||||
'id',
|
||||
'nameFirstName',
|
||||
'nameLastName',
|
||||
'city',
|
||||
'emailsPrimaryEmail',
|
||||
'avatarUrl',
|
||||
'position',
|
||||
@@ -46,7 +45,6 @@ export const prefillPeople = async (
|
||||
id: BRIAN_CHESKY_ID,
|
||||
nameFirstName: 'Brian',
|
||||
nameLastName: 'Chesky',
|
||||
city: 'San Francisco',
|
||||
emailsPrimaryEmail: 'chesky@airbnb.com',
|
||||
avatarUrl:
|
||||
'https://twentyhq.github.io/placeholder-images/founders/brian-chesky.jpg',
|
||||
@@ -65,7 +63,6 @@ export const prefillPeople = async (
|
||||
id: DARIO_AMODEI_ID,
|
||||
nameFirstName: 'Dario',
|
||||
nameLastName: 'Amodei',
|
||||
city: 'San Francisco',
|
||||
emailsPrimaryEmail: 'amodei@anthropic.com',
|
||||
avatarUrl:
|
||||
'https://twentyhq.github.io/placeholder-images/founders/dario-amodei.jpg',
|
||||
@@ -84,7 +81,6 @@ export const prefillPeople = async (
|
||||
id: PATRICK_COLLISON_ID,
|
||||
nameFirstName: 'Patrick',
|
||||
nameLastName: 'Collison',
|
||||
city: 'San Francisco',
|
||||
emailsPrimaryEmail: 'collison@stripe.com',
|
||||
avatarUrl:
|
||||
'https://twentyhq.github.io/placeholder-images/founders/patrick-collison.jpg',
|
||||
@@ -103,7 +99,6 @@ export const prefillPeople = async (
|
||||
id: DYLAN_FIELD_ID,
|
||||
nameFirstName: 'Dylan',
|
||||
nameLastName: 'Field',
|
||||
city: 'San Francisco',
|
||||
emailsPrimaryEmail: 'field@figma.com',
|
||||
avatarUrl:
|
||||
'https://twentyhq.github.io/placeholder-images/founders/dylan-field.jpg',
|
||||
@@ -122,7 +117,6 @@ export const prefillPeople = async (
|
||||
id: IVAN_ZHAO_ID,
|
||||
nameFirstName: 'Ivan',
|
||||
nameLastName: 'Zhao',
|
||||
city: 'San Francisco',
|
||||
emailsPrimaryEmail: 'zhao@notion.com',
|
||||
avatarUrl:
|
||||
'https://twentyhq.github.io/placeholder-images/founders/ivan-zhao.jpg',
|
||||
|
||||
Reference in New Issue
Block a user