Compare commits

..
51 Commits
Author SHA1 Message Date
Paul Rastoinandprastoin 914cf5aafc [REQUIRES_FIELDS_CACHE_FLUSH]Fix field entity to flat field transpiler (#17096)
Following https://github.com/twentyhq/twenty/pull/16981

UniversalIdentifier is now required in the entity so no need to fallback
it
2026-01-12 14:07:15 +01:00
Paul Rastoinandprastoin a9a8ed7d6e Identify standard field do deploy until IS_WORKSPACE_CREATION_V2_ENABLED is enabled in prod (#16981)
fixes https://github.com/twentyhq/twenty/issues/16905

Do not merge until `IS_WORKSPACE_CREATION_V2_ENABLED` has been activated
by default, and so sync metadata has been deprecated by doing so. As the
sync metadata will attempt to insert `null` `applicationId` and
`universalIdentifier` values while creating a workspace

In this PR we're introducing a new `SyncableEntityRequired` which
enforces the non nullable `applicationId` and `universalIdentifier` on
extending entity

In this PR we also migrate the field metadata entity to extend the
required

This command will search for workspace field metadata entities that
aren't associated to an applicationId, dispatch them to either the
workspace-custom `applicationId` or the twenty-standard `applicationId`.
For the standard entities it will also set their universal identifier
based on the `STANDARD_OBJECTS` const hashmap

As the non nullable `applicationId` and `universalIdentifier`migration
won't pass in the first we've been using the save point and upgrade
command migration fallback pattern

Tested the command on a prod extract locally

Both `twenty-eng` and `twenty-for-twenty` have unexpected standard
objects
Please note that we will deprecate the `isCustom` and `standardId` col
later in the future

```ts
[Nest] 98971  - 01/01/2026, 3:18:00 PM     LOG [IdentifyStandardEntitiesCommand] Successfully validated 600/600 field metadata update(s) for workspace 9870323e-22c3-4d14-9b7f-5bdc84f7d6ee (309 custom, 291 standard)
[Nest] 98971  - 01/01/2026, 3:18:00 PM    WARN [IdentifyStandardEntitiesCommand] Found 35 warning(s) while processing field metadata for workspace 9870323e-22c3-4d14-9b7f-5bdc84f7d6ee. These fields will become custom.
```
2026-01-12 11:54:00 +01:00
Lucas Bordeauandprastoin a31d7d33e5 Made the code more resilient to stale value prop in date filter (#17038)
Fixes : https://github.com/twentyhq/twenty/issues/17035

There was a bad pattern which risked introduce this bug in
`turnRecordFilterIntoRecordGqlOperationFilter` after recent refactor of
date logic and date filters, which didn't create any bug during dev time
because it wasn't tested with value combinations that existed before the
refactor.

Code has been re-organized to make it resilient to any wrong value
combination.

Also fixed a small bug that appeared during QA with `DATE` filter type,
which was blocking the save button from disappearing after a save.
2026-01-12 11:34:38 +01:00
Paul RastoinandGitHub 28e79de7b0 Fix workspace application fk command re-run (#17018)
# Introduction
The command is not idempotent, try to create an already existing FK
fails
- Always dropping the FK before recreating it in order to prevent this
- Removed the `remoteTable` and `remoteServer` from the command

We still have the `hasRunOnce` static var that will avoid re running it
if a workspace successfully passed the migration

Note: This is shared between both the upgrade command and the typeorm
migration

## Test
locally
```ts
atedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object person (20202020-e674-48e5-a542-72570eee7213) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object pet (custom) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object surveyResult (custom) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object rocket (custom) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] All objects already have updatedBy field for workspace 20202020-1c25-4d02-bf25-6aeccf7ea419
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [AddWorkspaceForeignKeysMigrationCommand] Successfully run AddWorkspaceForeignKeysMigrationCommand
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Upgrade for workspace 20202020-1c25-4d02-bf25-6aeccf7ea419 completed.
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Running command on workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db 2/2
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Upgrading workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db from=1.14.0 to=1.15.0 2/2
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [MigratePageLayoutWidgetConfigurationCommand] Starting migration of page layout widget configurations for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [MigratePageLayoutWidgetConfigurationCommand] Found 0 widget(s) needing migration out of 16 total
query: SELECT COUNT(1) AS "cnt" FROM "workspace_3ixj3i1a5avy16ptijtb3lae3"."note" "note" WHERE ( (("note"."position" = $1)) ) AND ( "note"."deletedAt" IS NULL ) -- PARAMETERS: ["NaN"]
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [FixNanPositionValuesInNotesCommand] Found 0 note(s) with NaN position values in workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [FixNanPositionValuesInNotesCommand] No NaN position values to fix
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Starting backfill of updatedBy field for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object note (20202020-0b00-45cd-b6f6-6cd806fc6804) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object task (20202020-1ba1-48ba-bc83-ef7e5990ed10) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object dashboard (20202020-3840-4b6d-9425-0c5188b05ca8) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object workflowRun (20202020-4e28-4e95-a9d7-6c00874f843c) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object workflow (20202020-62be-406c-b9ca-8caa50d51392) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object opportunity (20202020-9549-49dd-b2b2-883999db8938) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object company (20202020-b374-4779-a561-80086cb2e17f) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object attachment (20202020-bd3d-4c60-8dca-571c71d4447a) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object person (20202020-e674-48e5-a542-72570eee7213) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] Object surveyResult (custom) already has updatedBy field, skipping
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [BackfillUpdatedByFieldCommand] All objects already have updatedBy field for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [AddWorkspaceForeignKeysMigrationCommand] Skipping has already been run once AddWorkspaceForeignKeysMigrationCommand
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Upgrade for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db completed.
[Nest] 17395  - 01/08/2026, 3:04:18 PM     LOG [UpgradeCommand] Command completed!
```
2026-01-08 14:12:57 +00:00
0623bbbf9a i18n - docs translations (#17020)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 15:18:07 +01:00
MarieandGitHub f414f4799b Enable switching field to group records by on existing kanban view (#17015)
Fixes https://github.com/twentyhq/twenty/issues/16982 and
https://github.com/twentyhq/private-issues/issues/403

Re-introducing the feature to allow to switch field to group records by
on a kanban view


https://github.com/user-attachments/assets/a552d3f2-7900-4771-b512-98cb99cdd8de
2026-01-08 13:08:06 +00:00
Raphaël BosiandGitHub c207214f0b Fix chart sorting (#16996)
I introduced a bug in the chart sorting in this PR:
https://github.com/twentyhq/twenty/pull/16794
This PR fixes this.

The sorting on the first axis is already done by the group by for
FIELD_ASC and FIELD_DESC. It is sorted also for the second axis but in
each group.
For instance, if I create a graph that displays the amount of sales on
each day of the week grouped by vendor
I can have for:
Monday: Vendor B, Vendor C
Tuesday: Vendor A, Vendor B
Wednesday: Vendor A, Vendor C
...
Inside each day the order of the vendor is correct, but by looking at
only one day, I can't know the order of all the vendors.
That is why we always need to sort the second axis.
2026-01-08 12:46:56 +00:00
Don KendallandGitHub 8630efc3d7 feat: helm chart (#16808)
# Add Helm Chart

- Introduces a Twenty Helm chart with sensible defaults: internal
Postgres/Redis, auto DB creation/user, migrations, TLS via cert-manager,
and quickstart docs.

## Feedback requested
- Handling replicas > 1 with local storage (warn/force S3?).
- Defaults/guards for ephemeral pods + S3.
2026-01-08 12:45:46 +00:00
Raphaël BosiandGitHub 22573ccf03 [DASHBOARDS] Select title input upon tab or widget creation (#17010)
Video QA:


https://github.com/user-attachments/assets/334bbac8-03a5-4eb2-98b7-78bab7abfccf
2026-01-08 12:37:36 +00:00
nitinandGitHub 7fff8c8234 [Dashboards] Fix chart axis label behavior (#17011)
- Axis labels now respect `axisNameDisplay` config when chart has no
data (previously always showed both) - fixed for bar and line charts
- Horizontal bar charts now correctly map axis settings to visual
positions:
    - "X axis" setting → bottom axis (value)
    - "Y axis" setting → left axis (category)
    
video QA



https://github.com/user-attachments/assets/5bf32294-9a5e-4aa6-b3fd-0d4e33608d14
2026-01-08 12:34:39 +00:00
7a8f795dce i18n - docs translations (#17014)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 13:32:14 +01:00
b27f2ca146 fix(graph): fix toggle click and multiple dropdown issues (#16874)
Fixes #16843

## Summary

This PR fixes two bugs in graph settings:

1. **Multiple dropdowns opening simultaneously** 
2. **Toggle switches not clickable**

---

## Fix 1: Multiple dropdowns

**File:**
[ChartSettingItem.tsx](https://github.com/twentyhq/twenty/blob/main/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/chart-settings/ChartSettingItem.tsx)

Added `closeAnyOpenDropdown()` before opening a new dropdown. This
follows the existing pattern used in:
-
[useCommandMenu.ts](https://github.com/twentyhq/twenty/blob/main/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts)
-
[RecordBoardDragSelect.tsx](https://github.com/twentyhq/twenty/blob/main/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDragSelect.tsx)
-
[useRecordGroupReorderConfirmationModal.ts](https://github.com/twentyhq/twenty/blob/main/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupReorderConfirmationModal.ts)

---

## Fix 2: Toggle switches not clickable

**File:**
[MenuItemToggle.tsx](https://github.com/twentyhq/twenty/blob/main/packages/twenty-ui/src/navigation/menu/menu-item/components/MenuItemToggle.tsx)
(twenty-ui)

### Investigation

I traced the toggle click flow and compared working vs non-working
usages:
- 
[SettingsRolesList.tsx](https://github.com/twentyhq/twenty/blob/main/packages/twenty-front/src/modules/settings/roles/components/SettingsRolesList.tsx)
- toggles work (MenuItemToggle directly in Dropdown)
- 
[ObjectOptionsDropdownRecordGroupsContent.tsx](https://github.com/twentyhq/twenty/blob/main/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupsContent.tsx)
- toggles work (MenuItemToggle in SelectableListItem)
- 
[ChartSettingItem.tsx](https://github.com/twentyhq/twenty/blob/main/packages/twenty-front/src/modules/command-menu/pages/page-layout/components/chart-settings/ChartSettingItem.tsx)
- toggles don't work (CommandMenuItemToggle in SelectableListItem)

The component structure and props were identical, so I examined the HTML
output.

### Root Cause

Found **nested `<label>` elements**:

```html
<!-- Before (problematic) -->
<label htmlFor="id123">           <!-- MenuItemToggle's outer label -->
  <div>...content...</div>
  <label>                         <!-- Toggle's internal label -->
    <input id="id123" type="checkbox">
  </label>
</label>
```

While `htmlFor` theoretically links to the checkbox, nested labels are
**invalid HTML** and can cause click propagation issues in certain
browser contexts (particularly when combined with React event handling
and `SelectableList` keyboard navigation).

### Solution
Changed `StyledToggleContainer` from `label` to `div`:

```diff
- const StyledToggleContainer = styled.label`
+ const StyledToggleContainer = styled.div`
```

The
[Toggle](https://github.com/twentyhq/twenty/blob/main/packages/twenty-ui/src/input/components/Toggle.tsx)
component already handles clicks via its internal label wrapper, so the
outer label was redundant.

Also removed unused `useId`, `htmlFor`, and `id` props that were only
needed for the label association.


## Testing

-  TypeScript checks pass on `twenty-ui`
-  TypeScript checks pass on `twenty-front`
- No breaking changes to
[MenuItemToggle](https://github.com/twentyhq/twenty/blob/main/packages/twenty-ui/src/navigation/menu/menu-item/components/MenuItemToggle.tsx)
API
- All existing usages of
[MenuItemToggle](https://github.com/twentyhq/twenty/blob/main/packages/twenty-ui/src/navigation/menu/menu-item/components/MenuItemToggle.tsx)
should continue working (and potentially work better)

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-08 12:05:32 +00:00
Aman RajandGitHub 7ce76277d2 Fix the crash of the app page when object view is configured to open only on record page. (#16977)
### Problem:
If the command menu page is kept opened while navigating to record show
page then the app crashes.

### Root cause

When navigatiing to a record show page while the command menu page is
kept opened, it tries to open the record show page with command menu
open, as its state were set to true , before navigating to a new page
along with the instance id of previous context which are used in the
current context while rendering the page. Hence, leading to an error
page.

### Changes

while navigation to a record show page the command menu open state is
set to false. This is to handle the navigation gracefully

Fixes: #16577
2026-01-08 11:51:07 +00:00
5864c69e45 i18n - translations (#17012)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 12:20:58 +01:00
e9b7ad21d2 Fix view picker small bugs (#16987)
This PR solves small bugs around the view picker.

- Couldn’t obtain optimistic update after a re-order of a view by drag
and drop, we needed to refresh the page
- Picking a new icon wouldn’t trigger optimistic update (same problem)
- Picking a new icon would change the view (difficult to understand
behavior)
- Picking a new icon would trigger left drawer collapse (z-index
problem)

Since core views are not being handled by object metadata items anymore,
and that all view logic is plugged on coreViewsState, this PR
implemented optimistic effect by upserting into this state.

Fixes https://github.com/twentyhq/twenty/issues/15422
Fixes https://github.com/twentyhq/twenty/issues/16986

# Before


https://github.com/user-attachments/assets/64099c21-df9f-4772-ab0d-9ea449aed761

# After


https://github.com/user-attachments/assets/f4e844b3-6530-4178-abdb-b7a10d2327b8

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-08 12:05:45 +01:00
Thomas TrompetteandGitHub 71fd05315c [IF/ELSE] Capitalize branch titles + remove ending separator (#17009)
Before : if - else if not capitalized, ending separator)
<img width="496" height="451" alt="Capture d’écran 2026-01-08 à 11 17
29"
src="https://github.com/user-attachments/assets/621e92f3-02ed-4e71-9893-576543922871"
/>

After
<img width="496" height="431" alt="Capture d’écran 2026-01-08 à 11 17
14"
src="https://github.com/user-attachments/assets/549c146c-00b0-4162-b395-ceb05baf34b1"
/>
2026-01-08 10:28:15 +00:00
0d9245b684 i18n - docs translations (#17008)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 11:26:54 +01:00
3e08f295d5 i18n - translations (#17007)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 10:50:39 +01:00
c82ac19657 i18n - translations (#17005)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 10:39:04 +01:00
WeikoandGitHub 66b2882ac4 BREAKING CHANGE: Removing remote integration feature (#17001)
## Context
The feature has not been maintained for more than a year and was never
officially launched.
This PR removes its code due to the upcoming refactoring of the
sync-metadata that will break its logic if not handled properly and it
would be too costly for the time being.

TODO:
- remove isRemote from object/field metadata
2026-01-08 09:14:51 +00:00
Raphaël BosiandGitHub 2e0eeda52e [DASHBOARDS] Fix dashboard duplication createdBy (#16999)
Fixes https://github.com/twentyhq/core-team-issues/issues/2032

## Before


https://github.com/user-attachments/assets/5804d3e7-1c03-4eb9-9203-64656438f5d1


## After


https://github.com/user-attachments/assets/9f96458c-d2a5-481a-b6b2-4d88f0daa98a
2026-01-08 09:13:43 +00:00
nitinandGitHub d653b0a168 Change bar chart tooltips interaction from bar to slice (#16938)
https://github.com/user-attachments/assets/90baca7e-2c32-448d-a458-e95ced00fdf4


https://github.com/user-attachments/assets/53dd5f8b-1c22-4600-b582-46ba594b966a




https://github.com/user-attachments/assets/0b0b15c1-3ff8-4059-bc10-969d49852545
2026-01-08 09:06:44 +00:00
e0107f67fd i18n - docs translations (#17004)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 09:57:58 +01:00
bb9f243fd0 i18n - docs translations (#17002)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-08 09:03:50 +01:00
0e49b67b7d i18n - docs translations (#17000)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-07 19:22:56 +01:00
EtienneandGitHub 615ef1abdc Fix kanban view when grouping select field has null value (#16998) 2026-01-07 17:55:54 +00:00
1f0fac195c i18n - docs translations (#16993)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-07 18:54:45 +01:00
Raphaël BosiandGitHub 7af98a9c15 Update updatedat field on dashboards after edition (#16964)
Closes https://github.com/twentyhq/core-team-issues/issues/1896
2026-01-07 17:14:24 +00:00
nitinandGitHub a19ed92429 fix: composite field matching in relation field orderBy with groupBy (#16992)
- Fix groupBy field matching for composite fields nested within relation
fields
- Add `nestedSubFieldName` comparison when the nested field is a
composite type (CURRENCY, FULL_NAME, ADDRESS, etc.)
2026-01-07 16:13:08 +00:00
e83e616fde fix: qs's arrayLimit bypass in its bracket notation allows DoS via memory exhaustion (#16886)
Resolves [Dependabot Alert
354](https://github.com/twentyhq/twenty/security/dependabot/354) and
[Dependabot Alert
355](https://github.com/twentyhq/twenty/security/dependabot/355).

Upgraded express by one minor version. Removed redundant type definition
in root `package.json` since we already have it in twenty-server's
`package.json`.

Upgraded body-parser patch version in serverless package.json.

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-01-07 15:58:12 +00:00
Thomas TrompetteandGitHub 6410157c5c Provide executed step output instead of result (#16991)
For huge workflows, after 20 steps, we stop the job and re-trigger a new
one.
But some of those workflows actually never stop.
See https://github.com/twentyhq/private-issues/issues/401 

Here is a first issue. We resuming the workflow, we were providing the
result instead of the output
2026-01-07 15:50:14 +00:00
Charles BochetandGitHub 9acf6ce1ad Add otel collector to reserved subdomains (#16988)
Ordered the RESERVED_SUBDOMAINS list by alphabetical order and added
'otel-collector'
2026-01-07 15:11:34 +00:00
370609a2e2 i18n - translations (#16989)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-07 16:21:49 +01:00
Raphaël BosiandGitHub 4faed25624 [PAGE LAYOUTS] Add widgets validation (#16635)
- Add widget validation
- Remove 'None' option for primary axis group by
- Fix error message parsing by passing the operation type in
`useMetadataErrorHandler`
2026-01-07 15:00:13 +00:00
701a713042 Updated the user guide with new article + updated old content (#16955)
- more details on rate at which messages are imported from Gmail
- Settings -> Release deprecated to Settings -> Updates => this leads to
updating the file title, file name and the navigation files
- Support & Documentation accessible via Settings and no longer the nav
bar
- updated features out of the lab
- no more integration page
- added a new article with step by step on how to notify a teammate of a
note to review

docs.json is updated only for the English part

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-07 14:17:13 +00:00
EtienneandGitHub 81afc8b9ca Fix memory crash when creating record in table view (#16984)
**Bug Fixed**
Creating a new record in the People table view caused a browser memory
crash ("Paused before potential out of memory crash").
**Root Cause**
In useResetVirtualizationBecauseDataChanged.ts, when creating a record,
a loop iterated from 0 to totalNumberOfRecordsToVirtualize (the total
database count).
**Fix Applied**
Changed the loop to only iterate through indices from actually loaded
pages

Fixes https://github.com/twentyhq/twenty/issues/16980
2026-01-07 14:06:32 +00:00
Rajdeep DasandGitHub a4daead678 Fix view field updates not persisting (#16672)
Fixes an issue where column width changes and other view field
modifications were not persisted, and a toast error was shown.

**Root Causes:**
1. Frontend was using client-generated IDs instead of database IDs for
updates
2. Backend cache was stale, causing `View field to update not found`
error

**Changes:**
- Use the existing database ID when updating view fields
- Exclude client-generated IDs when creating new view fields  
- Invalidate flat entity maps cache before/after view field operations
- Refresh both view and view field caches to prevent validation errors

Fixes #16417 
Closes #16381
2026-01-07 13:56:43 +00:00
Paul RastoinandGitHub 4ea4572924 Workspace creation prefill fix (#16983)
# Introduction
Fixing prefill in v2 workspace creation code flow
2026-01-07 13:51:21 +00:00
Abdul RahmanandGitHub 10de7acef3 If else node tests (#16916) 2026-01-07 10:37:37 +00:00
nitinandGitHub e6b5ae825c fix purple color palette (#16972)
before - 

<img width="490" height="181" alt="CleanShot 2026-01-06 at 23 20 50"
src="https://github.com/user-attachments/assets/939897c1-3a8d-4a38-a586-98667e69f011"
/>

now - 

<img width="494" height="170" alt="CleanShot 2026-01-06 at 23 20 03"
src="https://github.com/user-attachments/assets/634676c4-ea28-4ead-b3da-49ca75b57bd1"
/>
2026-01-07 09:30:41 +00:00
e4f8d804d5 fix(16819): Add NoteDeleteOnePostQueryHook for soft removing note targets (#16826)
Fixes [#16819](https://github.com/twentyhq/twenty/issues/16819)

Added a post-query hook (NoteDeleteOnePostQueryHook) that automatically
soft-deletes all associated noteTarget records when a note is deleted.

## Key changes:

Created `note-delete-one.post-query.hook.ts`
Uses `GlobalWorkspaceOrmManager` to access workspace entities correctly
Executes in the proper workspace context to ensure data isolation
Soft-deletes noteTarget records to maintain referential consistency

## Testing
1. Company notes
Create a Company
Create and attach a Note to the Company
Navigate to Company → Notes page (should display the note)
Delete the Note
Navigate to Company → Notes page (should no longer crash)
Restore the Note (should appear again)
Delete and destroy the Note permanently
Navigate to Company → Notes page (should still work, just empty)

2. Opportunity notes
Create an Opportunity
Create and attach a Note to the Opportunity
Navigate to Opportunity → Notes page (should display the note)
Delete the Note
Navigate to Opportunity → Notes page (should no longer crash)
Restore the Note (should appear again)
Delete and destroy the Note permanently
Navigate to Opportunity → Notes page (should still work, just empty)

### Expected behavior:

Company Notes page remains functional at all stages
No console errors
Deleted notes properly excluded from the view
Other notes on the same Company remain accessible
Additional Notes
This fix ensures data consistency by maintaining the relationship
between notes and their targets throughout the deletion lifecycle.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
2026-01-07 08:30:08 +00:00
Félix MalfaitandGitHub 5f4b6e7ea4 Set default SMTP value to true (#16967)
As per title. Will make it easier for self-hosters. @Weiko fyi
2026-01-06 18:25:33 +00:00
a46619ec55 fix: enable save button when changing currency default value (#16864)
Closes #16792

## Problem

When editing a currency field’s default value (for example, changing
from **USD** to **UYU**), the **Save** button remained disabled.
However, if the format setting was changed first (**short → full →
short**), the Save button would then work correctly for currency
changes.

## Root Cause

The form was using **React Hook Form’s `values` mode**, which did not
properly track dirty state for the `defaultValue` and `settings` fields.

## Solution

Switched to the **`defaultValues` + `reset()`** pattern:

- Initialize the form with `defaultValues` (using placeholder values)
- Call `reset()` when `fieldMetadataItem` loads

This correctly tracks dirty state by comparing against the most recent
`reset` values.

## Note

A similar pattern is used in:
- `useWebhookForm`
- `useImapSmtpCaldavConnectionForm`

Those hooks call `reset()` via query callbacks. In this case, `reset()`
is called inside a `useEffect` because the data comes from synchronous
Recoil state rather than an async query.

Found two solutions to the problem, created commits for both. I feel the
useEffect pattern makes more sense here since it's cleaner in terms of
code.

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-01-06 18:02:43 +00:00
neo773andGitHub 971ddc0bb4 fix calendar save events transaction (#16763) 2026-01-06 17:56:03 +00:00
MarieandGitHub ceba0972cd Remove tests run on push on main (#16971)
Since tests are now run in the pre-merge queue with the latest main
version, they need not to be run again when merged into main, it would
be the exact same thing
2026-01-06 17:53:08 +00:00
Charles BochetandGitHub d53ec8f3c4 fix e2e tests (#16970)
As per title!
2026-01-06 18:52:15 +01:00
Thomas TrompetteandGitHub 6043edd53f Add metrics for completed and failed jobs (#16969)
Add a counter for completed and failed jobs
2026-01-06 18:51:54 +01:00
Thomas TrompetteandGitHub 2c5a7570fc Clean workflow run stoppage flag (#16950)
Flag has never been removed. Feature allows to stop a running workflow
run.
2026-01-06 17:05:46 +01:00
1113c20d89 Destroy core view (#16868)
Solution for #16526

---------

Co-authored-by: prastoin <paul@twenty.com>
2026-01-06 17:00:10 +01:00
MarieandGitHub 12189b378f Fix add related records to activity target after object renaming (#16953)
Fixes https://github.com/twentyhq/twenty/issues/16928 and
https://github.com/twentyhq/private-issues/issues/400

When an object is renamed, its corresponding relation field on
noteTarget and taskTarget are not renamed. This caused an issue as in
the FE, we used the related record object name to compute the field name
used in the payload.
This PR addresses it by, instead, finding the field name after
identifying it thanks to the object id.

To reproduce, you can rename an object then try to tie it to a note.
2026-01-06 16:26:26 +01:00
MarieandGitHub 13bc04047e [E2E tests] Fix run E2E tests before merge - attempt #3 (#16961) 2026-01-06 15:56:39 +01:00
718 changed files with 31767 additions and 19676 deletions
+1 -16
View File
@@ -1,10 +1,6 @@
name: CI Front and E2E
on:
push:
branches:
- main
pull_request:
merge_group:
@@ -351,7 +347,7 @@ jobs:
if: contains(needs.*.result, 'failure')
run: exit 1
ci-e2e-status-check:
if: always() && !cancelled() && github.event_name != 'merge_group'
if: always() && !cancelled()
timeout-minutes: 5
runs-on: ubuntu-latest
needs: [changed-files-check-e2e, e2e-test]
@@ -359,14 +355,3 @@ jobs:
- name: Fail job if any needs failed
if: contains(needs.*.result, 'failure')
run: exit 1
ci-e2e-merge-queue-check:
if: |
always() && !cancelled() && github.event_name == 'merge_group'
timeout-minutes: 5
runs-on: ubuntu-latest
name: ${{ github.event_name == 'merge_group' && 'ci-e2e-merge-queue-check' || 'ci-e2e-status-check' }}
needs: [changed-files-check-e2e, e2e-test]
steps:
- name: Fail job if any needs failed
if: contains(needs.*.result, 'failure')
run: exit 1
+1 -3
View File
@@ -1,9 +1,7 @@
name: CI SDK
on:
push:
branches:
- main
merge_group:
pull_request:
+2 -4
View File
@@ -1,12 +1,10 @@
name: CI Server
on:
push:
branches:
- main
pull_request:
merge_group:
permissions:
contents: read
+1 -3
View File
@@ -1,9 +1,7 @@
name: CI Shared
on:
push:
branches:
- main
merge_group:
pull_request:
@@ -4,6 +4,8 @@ permissions:
contents: read
on:
merge_group:
pull_request:
concurrency:
+1 -3
View File
@@ -4,9 +4,7 @@ permissions:
contents: read
on:
push:
branches:
- main
merge_group:
pull_request:
-1
View File
@@ -109,7 +109,6 @@
"@types/bytes": "^3.1.1",
"@types/chrome": "^0.0.267",
"@types/deep-equal": "^1.0.1",
"@types/express": "^4.17.13",
"@types/fs-extra": "^11.0.4",
"@types/graphql-fields": "^1.3.6",
"@types/inquirer": "^9.0.9",
@@ -0,0 +1,7 @@
apiVersion: v2
name: twenty
description: A Helm chart to deploy Twenty CRM (server + worker) with optional PostgreSQL and Redis dependencies.
type: application
version: 0.1.0
appVersion: "v1.14.0"
icon: https://raw.githubusercontent.com/twentyhq/twenty/2f25922f4cd5bd61e1427c57c4f8ea224e1d552c/packages/twenty-website/public/images/core/logo.svg
@@ -0,0 +1,51 @@
# Twenty Helm Chart - Quick Install
## Simple Install
Set your domain and install:
```bash
export DOMAIN=crm.example.com
helm install my-twenty ./packages/twenty-docker/helm/twenty \
--namespace twentycrm --create-namespace --wait \
--set "server.ingress.hosts[0].host=$DOMAIN" \
--set "server.ingress.tls[0].hosts[0]=$DOMAIN"
```
That's it! The chart will:
- Auto-generate a secure access token
- Create the PostgreSQL database "twenty" and schema "core" automatically
- Run TypeORM migrations via server init
- Enable TLS via cert-manager (acme: true by default for letsencrypt-prod)
## Access the App
Visit: `https://$DOMAIN`
Sign up to create your admin account through the web UI.
## Retrieve System Credentials
App secret token (for configuration/integrations):
```bash
kubectl get secret tokens -n twentycrm -o jsonpath='{.data.accessToken}' | base64 --decode && echo
```
Internal PostgreSQL credentials are managed by the chart and not exposed by default. If you need direct access, create your own user in the database pod or use an external PostgreSQL instance.
Jobs for DB creation and migrations have been removed to simplify deployments; the server handles readiness and migrations at startup.
## Advanced Configuration
See [full README](README.md) for:
- External PostgreSQL/Redis
- S3 storage configuration
- Custom resource limits
## Uninstall
```bash
helm uninstall my-twenty -n twentycrm
kubectl delete namespace twentycrm
```
@@ -0,0 +1,86 @@
# Twenty Helm Chart
Deploy Twenty CRM on Kubernetes with server, worker, PostgreSQL, and Redis components.
## Features
- Server and worker deployments with full env exposure via `values.yaml`.
- Internal PostgreSQL (Spilo) and Redis deployments included.
- PVC-based persistence using dynamic storage classes (no static PV manifests).
- Ingress with configurable annotations, hosts, and TLS.
- Database readiness and migrations handled by server/worker init containers by default.
Standard Kubernetes Jobs for DB creation/user and migrations have been removed to simplify installs. Readiness and migrations run in init containers.
## Quick Start
See [QUICKSTART.md](QUICKSTART.md) for a simple 2-line install with your domain.
## Installing
**Prerequisites:** Kubernetes 1.21+, Helm 3.8+, default StorageClass
Internal DB + Redis (default):
```bash
helm install my-twenty ./packages/twenty-docker/helm/twenty \
--namespace twentycrm --create-namespace
```
External DB/Redis:
```bash
helm install my-twenty ./packages/twenty-docker/helm/twenty \
--namespace twentycrm --create-namespace \
--set db.enabled=false \
--set db.external.host=db.example.com \
--set redisInternal.enabled=false
```
## Key Values
See `values.yaml` for a comprehensive list.
## Notes
- Database URL and Redis URL are composed automatically from chart settings
- Database `twenty` and schema `core` are created automatically by server init container
- No optional jobs: the chart no longer provides separate Jobs for DB or migrations.
- Access token auto-generated (32 chars) if not provided; reuses existing secret if present
- For production, provide a strong `secrets.tokens.accessToken` value via a secure values file; the auto-generated token is a convenience fallback.
- TLS enabled by default via cert-manager (`acme: true`)
- Requires default StorageClass for PVC provisioning
## Testing
```bash
helm lint ./packages/twenty-docker/helm/twenty
helm template my-twenty ./packages/twenty-docker/helm/twenty
helm plugin install https://github.com/quintush/helm-unittest
helm unittest ./packages/twenty-docker/helm/twenty
```
## Storage
**Local (default):** Uses PVCs for persistence
**S3:** Set `storage.type=s3` and provide credentials using a values file. You can either pass credentials directly or reference an existing Kubernetes Secret.
```bash
# values-secrets.yaml (do not commit)
# storage:
# type: s3
# s3:
# bucket: my-bucket
# region: us-east-1
# # Option A: direct values
# accessKeyId: AKIA...
# secretAccessKey: ...
# # Option B: reference a Secret
# # secretName: my-s3-creds
# # accessKeyIdKey: accessKeyId
# # secretAccessKeyKey: secretAccessKey
helm install my-twenty ./packages/twenty-docker/helm/twenty -f values-secrets.yaml
```
## Production Tips
- **Image versioning:** The chart defaults to `Chart.yaml`'s `appVersion` (currently v1.14.0). Override via `image.tag` in values to pin a different version or use `latest` for rolling updates.
- **Keep secrets secure:** Avoid `--set` for sensitive values; use `-f values-secrets.yaml` or reference existing Kubernetes Secrets via `server.extraEnvFrom`.
- S3 credentials can be referenced via `storage.s3.secretName + accessKeyIdKey/secretAccessKeyKey` to avoid embedding them in pod specs.
@@ -0,0 +1,17 @@
Thank you for installing Twenty!
To access the application:
- If ingress enabled:
{{- if and .Values.server.ingress.enabled (gt (len .Values.server.ingress.hosts) 0) }}
- Primary host: {{ (index .Values.server.ingress.hosts 0).host | default "<set a host>" }}
{{- else }}
- Primary host: <set a host>
{{- end }}
- URL: {{ include "twenty.serverUrl" . }}
- If ingress disabled: expose the service as needed (e.g., `kubectl port-forward svc/{{ include "twenty.fullname" . }}-server 3000:{{ .Values.server.service.port }}` or create a LoadBalancer/NodePort).
Configuration:
- Using internal DB: {{ ternary "yes" "no" .Values.db.enabled }}
- Using external DB: {{ ternary "yes" "no" (not .Values.db.enabled) }}
- Using internal Redis: {{ ternary "yes" "no" .Values.redisInternal.enabled }}
@@ -0,0 +1,172 @@
{{- define "twenty.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "twenty.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- define "twenty.namespace" -}}
{{ .Release.Namespace }}
{{- end -}}
{{/* Server image fields merged with globals */}}
{{- define "twenty.server.image" -}}
{{- $repo := default $.Values.image.repository (index $.Values.server.image "repository" | default "") -}}
{{- $tag := default (default $.Chart.AppVersion $.Values.image.tag) (index $.Values.server.image "tag" | default "") -}}
{{- $pp := default $.Values.image.pullPolicy (index $.Values.server.image "pullPolicy" | default "") -}}
{{- printf "%s:%s|%s" $repo $tag $pp -}}
{{- end -}}
{{/* Worker image fields merged with globals */}}
{{- define "twenty.worker.image" -}}
{{- $repo := default $.Values.image.repository (index $.Values.worker.image "repository" | default "") -}}
{{- $tag := default (default $.Chart.AppVersion $.Values.image.tag) (index $.Values.worker.image "tag" | default "") -}}
{{- $pp := default $.Values.image.pullPolicy (index $.Values.worker.image "pullPolicy" | default "") -}}
{{- printf "%s:%s|%s" $repo $tag $pp -}}
{{- end -}}
{{/* Extract parts of image helper */}}
{{- define "twenty.image.repository" -}}
{{- regexFind "^([^:|]+)" . -}}
{{- end -}}
{{- define "twenty.image.tag" -}}
{{- regexFind ":([^|]+)" . | trimPrefix ":" -}}
{{- end -}}
{{- define "twenty.image.pullPolicy" -}}
{{- regexFind "\\|(.+)$" . | trimPrefix "|" -}}
{{- end -}}
{{/* Compose DB connection URL */}}
{{- define "twenty.dbUrl" -}}
{{- if .Values.server.env.PG_DATABASE_URL -}}
{{- .Values.server.env.PG_DATABASE_URL -}}
{{- else if .Values.db.enabled -}}
{{- $host := printf "%s-db" (include "twenty.fullname" .) -}}
{{- $user := .Values.db.internal.appUser | default "twenty_app_user" -}}
{{- $pass := .Values.db.internal.appPassword | default (randAlphaNum 32) -}}
{{- $db := .Values.db.internal.database | default "twenty" -}}
{{- printf "postgres://%s:%s@%s.%s.svc.cluster.local/%s" $user $pass $host (include "twenty.namespace" .) $db -}}
{{- else -}}
{{- $scheme := "postgres" -}}
{{- $host := .Values.db.external.host -}}
{{- $port := .Values.db.external.port | default 5432 -}}
{{- $user := .Values.db.external.user | default "postgres" -}}
{{- $pass := .Values.db.external.password | default "postgres" -}}
{{- $db := .Values.db.external.database | default "twenty" -}}
{{- $qs := ternary "?sslmode=require" "" (eq .Values.db.external.ssl true) -}}
{{- printf "%s://%s:%s@%s:%v/%s%s" $scheme $user $pass $host $port $db $qs -}}
{{- end -}}
{{- end -}}
{{/* Compose Redis URL */}}
{{- define "twenty.redisUrl" -}}
{{- if .Values.server.env.REDIS_URL -}}
{{- .Values.server.env.REDIS_URL -}}
{{- else if .Values.redisInternal.enabled -}}
{{- $host := printf "%s-redis" (include "twenty.fullname" .) -}}
{{- printf "redis://%s.%s.svc.cluster.local:6379" $host (include "twenty.namespace" .) -}}
{{- else -}}
{{- $host := .Values.redis.external.host | default "redis" -}}
{{- $port := .Values.redis.external.port | default 6379 -}}
{{- printf "redis://%s:%v" $host $port -}}
{{- end -}}
{{- end -}}
{{/* Compose Server URL from ingress, else service */}}
{{- define "twenty.serverUrl" -}}
{{- if and .Values.server.ingress.enabled (gt (len .Values.server.ingress.hosts) 0) -}}
{{- $host := (index .Values.server.ingress.hosts 0).host -}}
{{- $tls := gt (len .Values.server.ingress.tls) 0 -}}
{{- $scheme := ternary "https" "http" $tls -}}
{{- $port := ternary 443 80 $tls -}}
{{- printf "%s://%s:%v" $scheme $host $port -}}
{{- else -}}
{{- $svc := printf "%s-server" (include "twenty.fullname" .) -}}
{{- $ns := include "twenty.namespace" . -}}
{{- $port := .Values.server.service.port | default 3000 -}}
{{- printf "http://%s.%s.svc.cluster.local:%v" $svc $ns $port -}}
{{- end -}}
{{- end -}}
{{/* Tokens secret name */}}
{{- define "twenty.secret.tokens.name" -}}
{{- .Values.secrets.tokens.name | default "tokens" -}}
{{- end -}}
{{/* Access token value: reuse existing secret if present, else provided value, else generated */}}
{{- define "twenty.secret.tokens.access" -}}
{{- $name := include "twenty.secret.tokens.name" . -}}
{{- $ns := include "twenty.namespace" . -}}
{{- $existing := lookup "v1" "Secret" $ns $name -}}
{{- if and $existing $existing.data.accessToken -}}
{{- b64dec $existing.data.accessToken -}}
{{- else if .Values.secrets.tokens.accessToken -}}
{{- .Values.secrets.tokens.accessToken -}}
{{- else -}}
{{- randAlphaNum 32 -}}
{{- end -}}
{{- end -}}
{{/* Server container port */}}
{{- define "twenty.server.containerPort" -}}
{{- .Values.server.service.port | default 3000 -}}
{{- end -}}
{{/* Storage type: prefer top-level storage.type, else legacy server.env.STORAGE_TYPE, else local */}}
{{- define "twenty.storageType" -}}
{{- if .Values.storage.type -}}
{{- .Values.storage.type -}}
{{- else if .Values.server.env.STORAGE_TYPE -}}
{{- .Values.server.env.STORAGE_TYPE -}}
{{- else -}}
local
{{- end -}}
{{- end -}}
{{/* Additional storage env vars (e.g., S3) */}}
{{- define "twenty.storageEnv" -}}
{{- if eq (include "twenty.storageType" .) "s3" -}}
{{- with .Values.storage.s3.bucket }}
- name: STORAGE_S3_NAME
value: {{ . | quote }}
{{- end }}
{{- with .Values.storage.s3.region }}
- name: STORAGE_S3_REGION
value: {{ . | quote }}
{{- end }}
{{- with .Values.storage.s3.endpoint }}
- name: STORAGE_S3_ENDPOINT
value: {{ . | quote }}
{{- end }}
{{- if and .Values.storage.s3.secretName .Values.storage.s3.accessKeyIdKey }}
- name: STORAGE_S3_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ .Values.storage.s3.secretName | quote }}
key: {{ .Values.storage.s3.accessKeyIdKey | quote }}
{{- else }}
{{- with .Values.storage.s3.accessKeyId }}
- name: STORAGE_S3_ACCESS_KEY_ID
value: {{ . | quote }}
{{- end }}
{{- end }}
{{- if and .Values.storage.s3.secretName .Values.storage.s3.secretAccessKeyKey }}
- name: STORAGE_S3_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.storage.s3.secretName | quote }}
key: {{ .Values.storage.s3.secretAccessKeyKey | quote }}
{{- else }}
{{- with .Values.storage.s3.secretAccessKey }}
- name: STORAGE_S3_SECRET_ACCESS_KEY
value: {{ . | quote }}
{{- end }}
{{- end }}
{{- end -}}
{{- end -}}
@@ -0,0 +1,62 @@
{{- if .Values.db.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "twenty.fullname" . }}-db
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: db
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/component: db
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: db
spec:
volumes:
{{- if .Values.db.internal.persistence.enabled }}
- name: db-data
persistentVolumeClaim:
claimName: {{ if .Values.db.internal.persistence.existingClaim }}{{ .Values.db.internal.persistence.existingClaim }}{{ else }}{{ include "twenty.fullname" . }}-db{{ end }}
{{- end }}
containers:
- name: db
image: {{ .Values.db.internal.image.repository }}:{{ .Values.db.internal.image.tag }}
imagePullPolicy: {{ .Values.db.internal.image.pullPolicy | default "IfNotPresent" }}
env:
- name: PGUSER_SUPERUSER
valueFrom:
secretKeyRef:
name: {{ include "twenty.fullname" . }}-db-superuser
key: username
- name: PGPASSWORD_SUPERUSER
valueFrom:
secretKeyRef:
name: {{ include "twenty.fullname" . }}-db-superuser
key: password
- name: SPILO_PROVIDER
value: {{ .Values.db.internal.env.SPILO_PROVIDER | quote }}
- name: ALLOW_NOSSL
value: {{ .Values.db.internal.env.ALLOW_NOSSL | quote }}
ports:
- containerPort: 5432
name: tcp
protocol: TCP
resources:
{{- toYaml .Values.db.internal.resources | nindent 12 }}
{{- if .Values.db.internal.persistence.enabled }}
volumeMounts:
- name: db-data
mountPath: /home/postgres/pgdata
{{- end }}
{{- end }}
@@ -0,0 +1,57 @@
{{- if .Values.redisInternal.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "twenty.fullname" . }}-redis
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: redis
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/component: redis
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: redis
spec:
containers:
- name: redis
image: {{ .Values.redisInternal.image.repository }}:{{ .Values.redisInternal.image.tag }}
imagePullPolicy: {{ default "IfNotPresent" .Values.redisInternal.image.pullPolicy }}
command:
- redis-stack-server
args:
- "--port"
- {{ .Values.redisInternal.service.port | quote }}
- "--maxmemory-policy"
- "noeviction"
ports:
- containerPort: {{ .Values.redisInternal.service.port }}
name: redis
protocol: TCP
resources:
{{- toYaml .Values.redisInternal.resources | nindent 12 }}
volumeMounts:
- name: redis-data
mountPath: /data
volumes:
- name: redis-data
{{- if .Values.redisInternal.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.redisInternal.persistence.existingClaim | default (printf "%s-redis" (include "twenty.fullname" .)) }}
{{- else }}
emptyDir: {}
{{- end }}
{{- end }}
@@ -0,0 +1,196 @@
{{- if .Values.server.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "twenty.fullname" . }}-server
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: server
spec:
replicas: {{ .Values.server.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/component: server
strategy:
{{- if or .Values.server.dockerDataPersistence.enabled .Values.server.persistence.enabled }}
type: Recreate
{{- else }}
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
{{- end }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: server
spec:
securityContext:
{{- toYaml .Values.securityContext | nindent 8 }}
volumes:
{{- if .Values.server.dockerDataPersistence.enabled }}
- name: docker-data
persistentVolumeClaim:
claimName: {{ if .Values.server.dockerDataPersistence.existingClaim }}{{ .Values.server.dockerDataPersistence.existingClaim }}{{ else }}{{ include "twenty.fullname" . }}-docker-data{{ end }}
{{- end }}
{{- if .Values.server.persistence.enabled }}
- name: server-data
persistentVolumeClaim:
claimName: {{ if .Values.server.persistence.existingClaim }}{{ .Values.server.persistence.existingClaim }}{{ else }}{{ include "twenty.fullname" . }}-server{{ end }}
{{- end }}
initContainers:
- name: wait-for-db
image: postgres:16-alpine
command:
- sh
- -c
- |
until pg_isready -h {{ if .Values.db.enabled }}{{ include "twenty.fullname" . }}-db{{ else }}{{ .Values.db.external.host }}{{ end }} \
-p {{ if .Values.db.enabled }}5432{{ else }}{{ .Values.db.external.port | default 5432 }}{{ end }} \
-U postgres; do
echo "Waiting for database socket..."
sleep 2
done
echo "Database socket is ready!"
{{- if .Values.db.enabled }}
- name: ensure-database-exists
image: postgres:16-alpine
env:
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: {{ include "twenty.fullname" . }}-db-superuser
key: password
- name: APP_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "twenty.fullname" . }}-db-url
key: appPassword
command:
- sh
- -c
- |
DBNAME={{ .Values.db.internal.database | default "twenty" }}
APP_USER={{ .Values.db.internal.appUser | default "twenty_app_user" }}
export PGPASSWORD
export APP_PASSWORD
echo "Creating database ${DBNAME} if it doesn't exist..."
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d postgres -v db="${DBNAME}" -Atc "SELECT 1 FROM pg_database WHERE datname = :'db'" | grep -q 1 || \
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d postgres -v db="${DBNAME}" -c 'CREATE DATABASE :"db";'
echo "Creating app user ${APP_USER} if it doesn't exist..."
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d postgres -v app_user="${APP_USER}" -v app_password="${APP_PASSWORD}" <<'EOSQL'
DO
$do$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = :'app_user') THEN
EXECUTE format('CREATE USER %I WITH PASSWORD %L', :'app_user', :'app_password');
END IF;
END
$do$;
EOSQL
echo "Creating core schema and granting permissions..."
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v app_user="${APP_USER}" -c 'CREATE SCHEMA IF NOT EXISTS core'
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v db="${DBNAME}" -v app_user="${APP_USER}" -c 'GRANT ALL PRIVILEGES ON DATABASE :"db" TO :"app_user";'
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v app_user="${APP_USER}" -c 'GRANT ALL PRIVILEGES ON SCHEMA core TO :"app_user";'
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v app_user="${APP_USER}" -c 'GRANT ALL PRIVILEGES ON SCHEMA public TO :"app_user";'
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v app_user="${APP_USER}" -c 'GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA core TO :"app_user";'
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v app_user="${APP_USER}" -c 'GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO :"app_user";'
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v app_user="${APP_USER}" -c 'ALTER DEFAULT PRIVILEGES IN SCHEMA core GRANT ALL ON TABLES TO :"app_user";'
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v app_user="${APP_USER}" -c 'ALTER DEFAULT PRIVILEGES IN SCHEMA core GRANT ALL ON SEQUENCES TO :"app_user";'
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v app_user="${APP_USER}" -c 'ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO :"app_user";'
psql -h {{ include "twenty.fullname" . }}-db -p 5432 -U postgres -d "${DBNAME}" -v app_user="${APP_USER}" -c 'ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO :"app_user";'
echo "Database ${DBNAME} is ready."
{{- end }}
- name: run-migrations
{{- $img := include "twenty.server.image" . }}
image: {{ include "twenty.image.repository" $img }}:{{ include "twenty.image.tag" $img }}
imagePullPolicy: {{ include "twenty.image.pullPolicy" $img }}
command:
- sh
- -c
- >-
npx -y typeorm migration:run -d dist/database/typeorm/core/core.datasource
env:
- name: PG_DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ include "twenty.fullname" . }}-db-url
key: url
containers:
- name: server
{{- $img := include "twenty.server.image" . }}
image: {{ include "twenty.image.repository" $img }}:{{ include "twenty.image.tag" $img }}
imagePullPolicy: {{ include "twenty.image.pullPolicy" $img }}
env:
- name: SERVER_URL
value: {{ include "twenty.serverUrl" . | quote }}
- name: PG_DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ include "twenty.fullname" . }}-db-url
key: url
- name: REDIS_URL
value: {{ include "twenty.redisUrl" . | quote }}
- name: SIGN_IN_PREFILLED
value: {{ .Values.server.env.SIGN_IN_PREFILLED | quote }}
- name: STORAGE_TYPE
value: {{ include "twenty.storageType" . | quote }}
- name: ACCESS_TOKEN_EXPIRES_IN
value: {{ .Values.server.env.ACCESS_TOKEN_EXPIRES_IN | quote }}
- name: LOGIN_TOKEN_EXPIRES_IN
value: {{ .Values.server.env.LOGIN_TOKEN_EXPIRES_IN | quote }}
- name: APP_SECRET
valueFrom:
secretKeyRef:
name: {{ include "twenty.secret.tokens.name" . }}
key: accessToken
{{- $storageEnv := (include "twenty.storageEnv" .) }}
{{- if $storageEnv }}
{{ $storageEnv | nindent 12 }}
{{- end }}
ports:
- name: http-tcp
containerPort: {{ include "twenty.server.containerPort" . }}
protocol: TCP
livenessProbe:
httpGet:
path: /
port: {{ include "twenty.server.containerPort" . }}
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 5
readinessProbe:
httpGet:
path: /
port: {{ include "twenty.server.containerPort" . }}
initialDelaySeconds: 40
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 5
resources:
{{- toYaml .Values.server.resources | nindent 12 }}
volumeMounts:
{{- if .Values.server.dockerDataPersistence.enabled }}
- name: docker-data
mountPath: /app/docker-data
{{- end }}
{{- if .Values.server.persistence.enabled }}
- name: server-data
mountPath: /app/packages/twenty-server/.local-storage
{{- end }}
{{- with .Values.server.extraVolumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.server.stdin }}
stdin: {{ .Values.server.stdin }}
{{- end }}
{{- if .Values.server.tty }}
tty: {{ .Values.server.tty }}
{{- end }}
{{- end }}
@@ -0,0 +1,77 @@
{{- if .Values.worker.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "twenty.fullname" . }}-worker
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: worker
spec:
replicas: {{ .Values.worker.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/component: worker
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: worker
spec:
securityContext:
{{- toYaml .Values.securityContext | nindent 8 }}
initContainers:
- name: wait-for-db
image: postgres:16-alpine
command:
- sh
- -c
- |
until pg_isready -h {{ if .Values.db.enabled }}{{ include "twenty.fullname" . }}-db{{ else }}{{ .Values.db.external.host }}{{ end }} \
-p {{ if .Values.db.enabled }}5432{{ else }}{{ .Values.db.external.port | default 5432 }}{{ end }} \
-U postgres; do
echo "Waiting for database socket..."
sleep 2
done
echo "Database socket is ready!"
containers:
- name: worker
{{- $img := include "twenty.worker.image" . }}
image: {{ include "twenty.image.repository" $img }}:{{ include "twenty.image.tag" $img }}
imagePullPolicy: {{ include "twenty.image.pullPolicy" $img }}
command:
{{- toYaml .Values.worker.command | nindent 12 }}
env:
- name: SERVER_URL
value: {{ include "twenty.serverUrl" . | quote }}
- name: PG_DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ include "twenty.fullname" . }}-db-url
key: url
- name: REDIS_URL
value: {{ include "twenty.redisUrl" . | quote }}
- name: STORAGE_TYPE
value: {{ include "twenty.storageType" . | quote }}
- name: APP_SECRET
valueFrom:
secretKeyRef:
name: {{ include "twenty.secret.tokens.name" . }}
key: accessToken
{{- $storageEnv := (include "twenty.storageEnv" .) }}
{{- if $storageEnv }}
{{ $storageEnv | nindent 12 }}
{{- end }}
resources:
{{- toYaml .Values.worker.resources | nindent 12 }}
stdin: {{ default true .Values.worker.stdin }}
tty: {{ default true .Values.worker.tty }}
{{- end }}
@@ -0,0 +1,47 @@
{{- if and .Values.server.enabled .Values.server.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "twenty.fullname" . }}
namespace: {{ include "twenty.namespace" . }}
annotations:
{{- if .Values.server.ingress.acme }}
cert-manager.io/cluster-issuer: "letsencrypt-prod"
{{- end }}
{{- with .Values.server.ingress.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.server.ingress.className }}
ingressClassName: {{ .Values.server.ingress.className }}
{{- end }}
rules:
{{- range .Values.server.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- if .paths }}
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "twenty.fullname" $ }}-server
port:
name: http-tcp
{{- end }}
{{- else }}
- path: /
pathType: Prefix
backend:
service:
name: {{ include "twenty.fullname" $ }}-server
port:
name: http-tcp
{{- end }}
{{- end }}
{{- if .Values.server.ingress.tls }}
tls:
{{- toYaml .Values.server.ingress.tls | nindent 4 }}
{{- end }}
{{- end }}
@@ -0,0 +1,20 @@
{{- if and .Values.db.enabled .Values.db.internal.persistence.enabled (not .Values.db.internal.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "twenty.fullname" . }}-db
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: db
spec:
accessModes:
{{ toYaml .Values.db.internal.persistence.accessModes | nindent 4 }}
resources:
requests:
storage: {{ .Values.db.internal.persistence.size }}
{{- if .Values.db.internal.persistence.storageClass }}
storageClassName: {{ .Values.db.internal.persistence.storageClass }}
{{- end }}
{{- end }}
@@ -0,0 +1,20 @@
{{- if and .Values.server.enabled .Values.server.dockerDataPersistence.enabled (not .Values.server.dockerDataPersistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "twenty.fullname" . }}-docker-data
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: server
spec:
accessModes:
{{ toYaml .Values.server.dockerDataPersistence.accessModes | nindent 4 }}
resources:
requests:
storage: {{ .Values.server.dockerDataPersistence.size }}
{{- if .Values.server.dockerDataPersistence.storageClass }}
storageClassName: {{ .Values.server.dockerDataPersistence.storageClass }}
{{- end }}
{{- end }}
@@ -0,0 +1,20 @@
{{- if and .Values.server.enabled .Values.server.persistence.enabled (not .Values.server.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "twenty.fullname" . }}-server
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: server
spec:
accessModes:
{{ toYaml .Values.server.persistence.accessModes | nindent 4 }}
resources:
requests:
storage: {{ .Values.server.persistence.size }}
{{- if .Values.server.persistence.storageClass }}
storageClassName: {{ .Values.server.persistence.storageClass }}
{{- end }}
{{- end }}
@@ -0,0 +1,24 @@
{{- if .Values.db.enabled }}
{{- $ns := include "twenty.namespace" . -}}
{{- $existing := lookup "v1" "Secret" $ns (printf "%s-db-superuser" (include "twenty.fullname" .)) -}}
{{- $user := .Values.db.internal.env.PGUSER_SUPERUSER | default "postgres" -}}
{{- $pass := .Values.db.internal.env.PGPASSWORD_SUPERUSER | default "" -}}
{{- if and $existing $existing.data.password -}}
{{- $pass = (b64dec $existing.data.password) -}}
{{- else if eq $pass "" -}}
{{- $pass = randAlphaNum 32 -}}
{{- end }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "twenty.fullname" . }}-db-superuser
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: db
type: Opaque
stringData:
username: {{ $user | quote }}
password: {{ $pass | quote }}
{{- end }}
@@ -0,0 +1,22 @@
{{- $secretName := printf "%s-db-url" (include "twenty.fullname" .) -}}
{{- $existingSecret := lookup "v1" "Secret" (include "twenty.namespace" .) $secretName -}}
{{- $appPassword := "" -}}
{{- if $existingSecret -}}
{{- $appPassword = index $existingSecret.data "appPassword" | b64dec -}}
{{- else -}}
{{- $appPassword = .Values.db.internal.appPassword | default (randAlphaNum 32) -}}
{{- end -}}
{{- $appUser := .Values.db.internal.appUser | default "twenty_app_user" -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ $secretName }}
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: server
type: Opaque
stringData:
url: {{ printf "postgres://%s:%s@%s-db.%s.svc.cluster.local/%s" (urlquery $appUser) (urlquery $appPassword) (include "twenty.fullname" .) (include "twenty.namespace" .) (.Values.db.internal.database | default "twenty") | quote }}
appPassword: {{ $appPassword | quote }}
@@ -0,0 +1,13 @@
{{- if .Values.secrets.tokens.create }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.secrets.tokens.name | default "tokens" }}
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: tokens
stringData:
accessToken: {{ include "twenty.secret.tokens.access" . | quote }}
{{- end }}
@@ -0,0 +1,21 @@
{{- if .Values.db.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "twenty.fullname" . }}-db
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: db
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/component: db
ports:
- port: 5432
targetPort: 5432
protocol: TCP
name: postgres
{{- end }}
@@ -0,0 +1,21 @@
{{- if .Values.redisInternal.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "twenty.fullname" . }}-redis
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: redis
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/component: redis
ports:
- port: {{ .Values.redisInternal.service.port }}
targetPort: {{ .Values.redisInternal.service.port }}
protocol: TCP
name: redis
{{- end }}
@@ -0,0 +1,21 @@
{{- if .Values.server.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "twenty.fullname" . }}-server
namespace: {{ include "twenty.namespace" . }}
labels:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: server
spec:
type: {{ .Values.server.service.type | default "ClusterIP" }}
selector:
app.kubernetes.io/name: {{ include "twenty.name" . }}
app.kubernetes.io/component: server
ports:
- name: http-tcp
port: {{ .Values.server.service.port }}
targetPort: {{ include "twenty.server.containerPort" . }}
protocol: TCP
{{- end }}
@@ -0,0 +1,43 @@
suite: app user and database initialization
templates:
- templates/secret-db-url.yaml
- templates/deployment-server.yaml
release:
name: my-twenty
namespace: default
tests:
- it: db-url secret includes app password
template: templates/secret-db-url.yaml
set:
db.enabled: true
db.internal.appUser: twenty_app_user
asserts:
- isKind:
of: Secret
- equal:
path: metadata.name
value: my-twenty-twenty-db-url
- isNotEmpty:
path: stringData.appPassword
- it: server init container creates app user with proper permissions
template: templates/deployment-server.yaml
set:
db.enabled: true
db.internal.appUser: test_user
db.internal.database: testdb
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: CREATE USER
- it: db url uses app user not superuser
template: templates/secret-db-url.yaml
set:
db.enabled: true
db.internal.appUser: my_app
db.internal.database: mydb
asserts:
- matchRegex:
path: stringData.url
pattern: ^postgres://my_app:.*@my-twenty-twenty-db
@@ -0,0 +1,120 @@
suite: ingress rendering
templates:
- templates/ingress.yaml
release:
name: my-twenty
namespace: default
tests:
- it: renders with host and paths
set:
server.ingress.enabled: true
server.ingress.hosts:
- host: twenty.example.com
paths:
- path: /
pathType: Prefix
server.ingress.tls:
- hosts:
- twenty.example.com
secretName: twenty-tls
asserts:
- equal:
path: spec.rules[0].host
value: twenty.example.com
- equal:
path: spec.rules[0].http.paths[0].path
value: /
- equal:
path: spec.rules[0].http.paths[0].pathType
value: Prefix
- equal:
path: spec.tls[0].hosts[0]
value: twenty.example.com
- equal:
path: spec.tls[0].secretName
value: twenty-tls
- it: adds cert-manager annotation when acme is true
set:
server.ingress.enabled: true
server.ingress.acme: true
server.ingress.hosts:
- host: twenty.example.com
paths:
- path: /
pathType: Prefix
asserts:
- equal:
path: metadata.annotations["cert-manager.io/cluster-issuer"]
value: letsencrypt-prod
- it: supports multiple hosts with different paths
set:
server.ingress.enabled: true
server.ingress.hosts:
- host: twenty.example.com
paths:
- path: /
pathType: Prefix
- host: crm.example.com
paths:
- path: /api
pathType: Prefix
- path: /graphql
pathType: Exact
asserts:
- equal:
path: spec.rules[0].host
value: twenty.example.com
- equal:
path: spec.rules[1].host
value: crm.example.com
- equal:
path: spec.rules[1].http.paths[0].path
value: /api
- equal:
path: spec.rules[1].http.paths[1].path
value: /graphql
- equal:
path: spec.rules[1].http.paths[1].pathType
value: Exact
- it: does not render when ingress disabled
set:
server.ingress.enabled: false
asserts:
- hasDocuments:
count: 0
- it: supports custom annotations
set:
server.ingress.enabled: true
server.ingress.annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
custom.annotation/key: "value"
server.ingress.hosts:
- host: twenty.example.com
paths:
- path: /
pathType: Prefix
asserts:
- equal:
path: metadata.annotations["nginx.ingress.kubernetes.io/proxy-body-size"]
value: "50m"
- equal:
path: metadata.annotations["custom.annotation/key"]
value: "value"
- it: supports custom className
set:
server.ingress.enabled: true
server.ingress.className: nginx
server.ingress.hosts:
- host: twenty.example.com
paths:
- path: /
pathType: Prefix
asserts:
- equal:
path: spec.ingressClassName
value: nginx
@@ -0,0 +1,106 @@
suite: pvc configuration
templates:
- templates/pvc-server.yaml
- templates/pvc-db-internal.yaml
- templates/pvc-docker-data.yaml
release:
name: my-twenty
namespace: default
tests:
- it: server pvc renders when persistence enabled
template: templates/pvc-server.yaml
set:
server.persistence.enabled: true
server.persistence.size: 10Gi
asserts:
- isKind:
of: PersistentVolumeClaim
- equal:
path: metadata.name
value: my-twenty-twenty-server
- equal:
path: spec.resources.requests.storage
value: 10Gi
- contains:
path: spec.accessModes
content: ReadWriteOnce
- it: server pvc does not render when persistence disabled
template: templates/pvc-server.yaml
set:
server.persistence.enabled: false
asserts:
- hasDocuments:
count: 0
- it: server pvc renders with correct defaults
template: templates/pvc-server.yaml
set:
server.persistence.enabled: true
asserts:
- isKind:
of: PersistentVolumeClaim
- it: server pvc omits storageClassName when set to hyphen
template: templates/pvc-server.yaml
set:
server.persistence.enabled: true
server.persistence.storageClass: ""
asserts:
- isNull:
path: spec.storageClassName
- it: db-internal pvc renders with correct size
template: templates/pvc-db-internal.yaml
set:
db.enabled: true
db.internal.persistence.enabled: true
db.internal.persistence.size: 20Gi
asserts:
- isKind:
of: PersistentVolumeClaim
- equal:
path: metadata.name
value: my-twenty-twenty-db
- isKind:
of: PersistentVolumeClaim
- it: db-internal pvc does not render when disabled
template: templates/pvc-db-internal.yaml
set:
db.enabled: false
asserts:
- hasDocuments:
count: 0
- it: db-internal pvc renders when enabled
template: templates/pvc-db-internal.yaml
set:
db.enabled: true
db.internal.persistence.enabled: true
asserts:
- hasDocuments:
count: 1
- it: docker-data pvc renders when enabled
template: templates/pvc-docker-data.yaml
set:
server.enabled: true
server.dockerDataPersistence.enabled: true
server.dockerDataPersistence.size: 5Gi
asserts:
- isKind:
of: PersistentVolumeClaim
- it: all pvcs use ReadWriteOnce access mode
templates:
- templates/pvc-server.yaml
- templates/pvc-db-internal.yaml
set:
server.persistence.enabled: true
db.enabled: true
db.internal.persistence.enabled: true
asserts:
- contains:
path: spec.accessModes
content: ReadWriteOnce
@@ -0,0 +1,91 @@
suite: redis and database switching
templates:
- templates/deployment-redis-internal.yaml
- templates/service-redis-internal.yaml
- templates/deployment-db-internal.yaml
- templates/service-db-internal.yaml
release:
name: my-twenty
namespace: default
tests:
- it: internal redis deployment renders when enabled
template: templates/deployment-redis-internal.yaml
set:
redisInternal.enabled: true
asserts:
- isKind:
of: Deployment
- equal:
path: metadata.name
value: my-twenty-twenty-redis
- it: internal redis does not render when disabled
template: templates/deployment-redis-internal.yaml
set:
redisInternal.enabled: false
asserts:
- hasDocuments:
count: 0
- it: redis service renders when internal redis enabled
template: templates/service-redis-internal.yaml
set:
redisInternal.enabled: true
asserts:
- isKind:
of: Service
- equal:
path: metadata.name
value: my-twenty-twenty-redis
- it: redis uses args for port configuration
template: templates/deployment-redis-internal.yaml
set:
redisInternal.enabled: true
redisInternal.service.port: 6379
asserts:
- contains:
path: spec.template.spec.containers[0].args
content: --port
- contains:
path: spec.template.spec.containers[0].args
content: "6379"
- it: internal db deployment renders when enabled
template: templates/deployment-db-internal.yaml
set:
db.enabled: true
asserts:
- isKind:
of: Deployment
- equal:
path: metadata.name
value: my-twenty-twenty-db
- it: internal db does not render when disabled
template: templates/deployment-db-internal.yaml
set:
db.enabled: false
asserts:
- hasDocuments:
count: 0
- it: internal db uses Recreate strategy for PVC
template: templates/deployment-db-internal.yaml
set:
db.enabled: true
asserts:
- equal:
path: spec.strategy.type
value: Recreate
- it: db service renders when internal db enabled
template: templates/service-db-internal.yaml
set:
db.enabled: true
asserts:
- isKind:
of: Service
- equal:
path: metadata.name
value: my-twenty-twenty-db
@@ -0,0 +1,122 @@
suite: schema permissions (core for app tables, public for extensions)
templates:
- templates/deployment-server.yaml
release:
name: my-twenty
namespace: default
tests:
# Core Schema Tests
# ================
# Twenty uses a dedicated 'core' schema for all application tables and the TypeORM
# migrations tracking table. This provides namespace isolation and clarity.
- it: ensure-database-exists creates core schema
template: templates/deployment-server.yaml
set:
db.enabled: true
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: CREATE SCHEMA IF NOT EXISTS core
- it: app user gets all privileges on core schema
template: templates/deployment-server.yaml
set:
db.enabled: true
db.internal.appUser: twenty_app_user
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: GRANT ALL PRIVILEGES ON SCHEMA core
- it: app user gets all privileges on core tables
template: templates/deployment-server.yaml
set:
db.enabled: true
db.internal.appUser: twenty_app_user
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA core
- it: default privileges set for future core tables
template: templates/deployment-server.yaml
set:
db.enabled: true
db.internal.appUser: twenty_app_user
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: ALTER DEFAULT PRIVILEGES IN SCHEMA core GRANT ALL ON TABLES
- it: default privileges set for future core sequences
template: templates/deployment-server.yaml
set:
db.enabled: true
db.internal.appUser: twenty_app_user
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: ALTER DEFAULT PRIVILEGES IN SCHEMA core GRANT ALL ON SEQUENCES
# Public Schema Tests
# ==================
# PostgreSQL extensions (like unaccent for accent-insensitive text search) are
# created in the 'public' schema. Twenty's migrations create these functions, so
# the app user needs full privileges on the public schema as well.
- it: app user gets all privileges on public schema
template: templates/deployment-server.yaml
set:
db.enabled: true
db.internal.appUser: twenty_app_user
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: GRANT ALL PRIVILEGES ON SCHEMA public
- it: app user gets all privileges on public tables
template: templates/deployment-server.yaml
set:
db.enabled: true
db.internal.appUser: twenty_app_user
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public
- it: default privileges set for future public tables
template: templates/deployment-server.yaml
set:
db.enabled: true
db.internal.appUser: twenty_app_user
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES
- it: default privileges set for future public sequences
template: templates/deployment-server.yaml
set:
db.enabled: true
db.internal.appUser: twenty_app_user
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="ensure-database-exists")].command[2]
pattern: ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES
# TypeORM Migration Tests
# ======================
# TypeORM migrations are configured to use the core.datasource which targets the
# 'core' schema. This ensures the _typeorm_migrations table and all application
# tables use the dedicated core schema.
- it: migrations run against core datasource
template: templates/deployment-server.yaml
set:
db.enabled: true
asserts:
- matchRegex:
path: spec.template.spec.initContainers[?(@.name=="run-migrations")].command[2]
pattern: core\.datasource
@@ -0,0 +1,52 @@
suite: secret generation
templates:
- templates/secret-tokens.yaml
- templates/secret-db-superuser.yaml
- templates/secret-db-url.yaml
release:
name: my-twenty
namespace: default
tests:
- it: generates tokens
template: templates/secret-tokens.yaml
set:
secrets.tokens.create: true
asserts:
- isKind:
of: Secret
- equal:
path: metadata.name
value: tokens
# db-user secret removed; chart no longer manages app user credentials
- it: db-superuser secret generates password for internal DB
template: templates/secret-db-superuser.yaml
set:
db.enabled: true
asserts:
- isKind:
of: Secret
- equal:
path: metadata.name
value: my-twenty-twenty-db-superuser
- it: db-superuser secret does not render when internal DB disabled
template: templates/secret-db-superuser.yaml
set:
db.enabled: false
asserts:
- hasDocuments:
count: 0
- it: db-url secret renders for internal database
template: templates/secret-db-url.yaml
set:
db.enabled: true
db.internal.database: appdb
asserts:
- isKind:
of: Secret
- equal:
path: metadata.name
value: my-twenty-twenty-db-url
@@ -0,0 +1,71 @@
suite: server url
templates:
- templates/deployment-server.yaml
release:
name: my-twenty
namespace: default
tests:
- it: derives from ingress with paths
set:
server.ingress.enabled: true
server.ingress.hosts:
- host: crm.example.com
paths:
- path: /
pathType: Prefix
server.ingress.tls:
- secretName: example-tls
hosts:
- crm.example.com
asserts:
- equal:
path: spec.template.spec.containers[0].env[0].value
value: "https://crm.example.com:443"
- it: falls back to service when ingress disabled
set:
server.ingress.enabled: false
server.service.port: 3000
server.env.SERVER_URL: ""
asserts:
- matchRegex:
path: spec.template.spec.containers[0].env[0].value
pattern: ^http://my-twenty-twenty-server\.default\.svc\.cluster\.local:3000$
---
suite: ingress configuration
templates:
- templates/ingress.yaml
release:
name: my-twenty
namespace: default
tests:
- it: renders with host and paths
set:
server.ingress.hosts:
- host: twenty.example.com
paths:
- path: /
pathType: Prefix
server.ingress.tls:
- hosts:
- twenty.example.com
secretName: twenty-tls
asserts:
- equal:
path: spec.rules[0].host
value: twenty.example.com
- equal:
path: spec.rules[0].http.paths[0].path
value: /
- equal:
path: spec.tls[0].hosts[0]
value: twenty.example.com
- equal:
path: spec.tls[0].secretName
value: twenty-tls
- it: adds cert-manager annotation when acme true
set:
server.ingress.acme: true
asserts:
- equal:
path: metadata.annotations[cert-manager.io/cluster-issuer]
value: letsencrypt-prod
@@ -0,0 +1,46 @@
suite: storage env s3
templates:
- templates/deployment-server.yaml
release:
name: my-twenty
namespace: default
tests:
- it: injects S3 env vars when storage.type is s3
set:
storage.type: s3
storage.s3.bucket: my-bucket
storage.s3.region: us-east-1
storage.s3.endpoint: https://s3.amazonaws.com
storage.s3.accessKeyId: AKIA
storage.s3.secretAccessKey: secret
asserts:
- contains:
path: spec.template.spec.containers[0].env
content:
name: STORAGE_TYPE
value: s3
- contains:
path: spec.template.spec.containers[0].env
content:
name: STORAGE_S3_NAME
value: my-bucket
- contains:
path: spec.template.spec.containers[0].env
content:
name: STORAGE_S3_REGION
value: us-east-1
- contains:
path: spec.template.spec.containers[0].env
content:
name: STORAGE_S3_ENDPOINT
value: https://s3.amazonaws.com
- contains:
path: spec.template.spec.containers[0].env
content:
name: STORAGE_S3_ACCESS_KEY_ID
value: AKIA
- contains:
path: spec.template.spec.containers[0].env
content:
name: STORAGE_S3_SECRET_ACCESS_KEY
value: secret
@@ -0,0 +1,76 @@
suite: worker deployment
templates:
- templates/deployment-worker.yaml
release:
name: my-twenty
namespace: default
tests:
- it: renders with correct name and labels
asserts:
- isKind:
of: Deployment
- equal:
path: metadata.name
value: my-twenty-twenty-worker
- equal:
path: metadata.labels["app.kubernetes.io/name"]
value: twenty
- equal:
path: metadata.labels["app.kubernetes.io/component"]
value: worker
- it: uses db-url secret for database connection
set:
db.enabled: true
asserts:
- equal:
path: spec.template.spec.containers[0].env[?(@.name=="PG_DATABASE_URL")].valueFrom.secretKeyRef.name
value: my-twenty-twenty-db-url
- equal:
path: spec.template.spec.containers[0].env[?(@.name=="PG_DATABASE_URL")].valueFrom.secretKeyRef.key
value: url
- it: does not mount storage by default
asserts:
- isNull:
path: spec.template.spec.volumes
- it: uses correct command for worker process
asserts:
- contains:
path: spec.template.spec.containers[0].command
content: yarn
- contains:
path: spec.template.spec.containers[0].command
content: worker:prod
- it: sets replica count to 1 by default
asserts:
- equal:
path: spec.replicas
value: 1
- it: supports local storage configuration
set:
storage.type: local
asserts:
- equal:
path: spec.template.spec.containers[0].env[?(@.name=="STORAGE_TYPE")].value
value: local
- it: uses custom image when specified
set:
worker.image.repository: custom/twenty
worker.image.tag: v2.0.0
asserts:
- matchRegex:
path: spec.template.spec.containers[0].image
pattern: "^custom/twenty:v2.0.0$"
- it: falls back to Chart.AppVersion when tag not specified
set:
worker.image.tag: ""
asserts:
- matchRegex:
path: spec.template.spec.containers[0].image
pattern: ":v1.14.0$"
@@ -0,0 +1,182 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Twenty Helm Chart Values",
"type": "object",
"additionalProperties": true,
"properties": {
"image": {
"type": "object",
"properties": {
"repository": { "type": "string" },
"tag": { "type": "string" },
"pullPolicy": { "type": "string", "enum": ["Always", "IfNotPresent", "Never"] }
}
},
"nameOverride": { "type": "string" },
"fullnameOverride": { "type": "string" },
"namespaceOverride": { "type": "string" },
"secrets": {
"type": "object",
"properties": {
"tokens": {
"type": "object",
"properties": {
"create": { "type": "boolean" },
"name": { "type": "string" },
"accessToken": { "type": "string" }
},
"required": ["create", "name"]
}
}
},
"server": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"replicaCount": {
"type": "integer",
"minimum": 1,
"description": "Number of server replicas. When using local storage with ReadWriteOnce (RWO) PersistentVolumeClaims (the default), multiple replicas cannot share the same PVC and pods will fail to schedule if replicaCount > 1. Use replicaCount = 1 for local/RWO storage, or configure a shared storage backend such as S3 before increasing this value."
},
"podSecurityContext": { "type": "object" },
"containerSecurityContext": { "type": "object" },
"env": {
"type": "object",
"properties": {
"NODE_PORT": { "type": "integer", "minimum": 1 },
"PG_DATABASE_URL": { "type": "string" },
"REDIS_URL": { "type": "string" },
"SIGN_IN_PREFILLED": { "type": "string" },
"STORAGE_TYPE": { "type": "string" },
"ACCESS_TOKEN_EXPIRES_IN": { "type": "string" },
"LOGIN_TOKEN_EXPIRES_IN": { "type": "string" },
"EMAIL_DRIVER": { "type": "string" },
"EMAIL_SMTP_HOST": { "type": "string" },
"EMAIL_SMTP_PORT": { "type": "integer" },
"EMAIL_SMTP_USER": { "type": "string" },
"EMAIL_SMTP_PASSWORD": { "type": "string" },
"EMAIL_SMTP_NO_TLS": { "type": "boolean" },
"EMAIL_FROM_ADDRESS": { "type": "string" },
"EMAIL_FROM_NAME": { "type": "string" },
"EMAIL_SYSTEM_ADDRESS": { "type": "string" },
"IS_EMAIL_VERIFICATION_REQUIRED": { "type": "boolean" },
"EMAIL_VERIFICATION_TOKEN_EXPIRES_IN": { "type": "string" },
"PASSWORD_RESET_TOKEN_EXPIRES_IN": { "type": "string" }
}
},
"service": {
"type": "object",
"properties": {
"type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer"] },
"port": { "type": "integer", "minimum": 1 },
"sessionAffinity": { "type": "string", "enum": ["None", "ClientIP"] },
"sessionAffinityTimeoutSeconds": { "type": "integer", "minimum": 1 }
}
},
"ingress": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"className": { "type": "string" },
"acme": { "type": "boolean" },
"hosts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"host": { "type": "string" },
"paths": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": { "type": "string" },
"pathType": { "type": "string", "enum": ["Prefix", "Exact", "ImplementationSpecific"] }
}
}
}
}
}
},
"tls": { "type": "array" }
}
},
"persistence": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"existingClaim": { "type": "string" },
"storageClass": { "type": "string" },
"accessModes": { "type": "array", "items": { "type": "string" } },
"size": { "type": "string" }
}
},
"dockerDataPersistence": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"existingClaim": { "type": "string" },
"storageClass": { "type": "string" },
"accessModes": { "type": "array", "items": { "type": "string" } },
"size": { "type": "string" }
}
}
}
},
"worker": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"replicaCount": { "type": "integer", "minimum": 1 },
"podSecurityContext": { "type": "object" },
"containerSecurityContext": { "type": "object" },
"env": {
"type": "object",
"properties": {
"PG_DATABASE_URL": { "type": "string" },
"REDIS_URL": { "type": "string" },
"STORAGE_TYPE": { "type": "string" },
"DISABLE_DB_MIGRATIONS": { "type": "string" }
}
}
}
},
"storage": {
"type": "object",
"properties": {
"type": { "type": "string", "enum": ["local", "s3"] },
"s3": {
"type": "object",
"properties": {
"bucket": { "type": "string" },
"region": { "type": "string" },
"endpoint": { "type": "string" },
"accessKeyId": { "type": "string" },
"secretAccessKey": { "type": "string" },
"secretName": { "type": "string" },
"accessKeyIdKey": { "type": "string" },
"secretAccessKeyKey": { "type": "string" }
}
}
},
"required": ["type"],
"allOf": [
{
"if": { "properties": { "type": { "const": "s3" } }, "required": ["type"] },
"then": {
"required": ["s3"],
"properties": {
"s3": {
"required": ["bucket", "region", "accessKeyId", "secretAccessKey"]
}
}
}
}
]
}
}
}
@@ -0,0 +1,169 @@
# Default image used by all components
image:
repository: twentycrm/twenty
tag: "" # defaults to Chart.yaml appVersion
pullPolicy: IfNotPresent
nameOverride: ""
fullnameOverride: ""
# Global security context (uid/gid for all pods)
securityContext:
runAsUser: 1000
fsGroup: 1000
# Storage backend: local or s3
storage:
type: local
s3:
bucket: ""
region: ""
endpoint: ""
accessKeyId: ""
secretAccessKey: ""
# Auth tokens (random if not provided)
secrets:
tokens:
create: true
name: tokens
accessToken: ""
# Server deployment
server:
enabled: true
replicaCount: 1
image: {} # override repository/tag/pullPolicy per component
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1024Mi
env:
SIGN_IN_PREFILLED: "false"
ACCESS_TOKEN_EXPIRES_IN: "7d"
LOGIN_TOKEN_EXPIRES_IN: "1h"
service:
type: ClusterIP
port: 3000
ingress:
enabled: true
className: nginx
acme: true # add cert-manager annotation for Let's Encrypt
annotations: {}
hosts:
- host: crm.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: twenty-tls
hosts:
- crm.example.com
persistence:
enabled: true
size: 10Gi
storageClass: ""
existingClaim: ""
accessModes:
- ReadWriteOnce
dockerDataPersistence:
enabled: true
size: 100Mi
storageClass: ""
existingClaim: ""
accessModes:
- ReadWriteOnce
extraVolumeMounts: []
# Worker deployment
worker:
enabled: true
replicaCount: 1
image: {}
command: ["yarn", "worker:prod"]
resources:
requests:
cpu: 250m
memory: 1024Mi
limits:
cpu: 1000m
memory: 2048Mi
# PostgreSQL
db:
enabled: true
internal:
database: twenty
appUser: twenty_app_user
appPassword: "" # random if empty
image:
repository: twentycrm/twenty-postgres-spilo
tag: 3.3-p2
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1024Mi
persistence:
enabled: true
size: 10Gi
storageClass: ""
existingClaim: ""
accessModes:
- ReadWriteOnce
env:
PGUSER_SUPERUSER: postgres
PGPASSWORD_SUPERUSER: postgres
SPILO_PROVIDER: local
ALLOW_NOSSL: "true"
external:
host: ""
port: 5432
user: twenty_app_user
password: ""
database: twenty
ssl: false
# Redis
redisInternal:
enabled: true
image:
repository: redis/redis-stack-server
tag: 7.2.0-v10
pullPolicy: IfNotPresent
resources:
requests:
cpu: 250m
memory: 1024Mi
limits:
cpu: 500m
memory: 2048Mi
service:
port: 6379
persistence:
enabled: false
size: 1Gi
storageClass: ""
existingClaim: ""
accessModes:
- ReadWriteOnce
# External Redis (when redisInternal.enabled=false)
redis:
external:
host: ""
port: 6379
+20 -4
View File
@@ -1,11 +1,11 @@
# README
# Kubernetes for Twenty CRM (Helm)
DISCLAIMER: The k8s and podman deployments are not maintained by the core team.
These files are provided and maintained by the community. Twenty core team
maintains support for docker deployment.
## Overview
This repository contains Kubernetes manifests and Terraform files to help you deploy and manage the TwentyCRM application. The files are located in the `packages/twenty-docker/k8s` directory.
This repository contains a world-class Helm chart and (legacy) raw Kubernetes manifests plus Terraform files to help you deploy and manage the Twenty CRM application. The chart is located at `packages/twenty-docker/helm/twenty` and supersedes the manifests in `packages/twenty-docker/k8s/manifests`.
## Prerequisites
@@ -13,9 +13,25 @@ Before using these files, ensure you have the following installed and configured
- Kubernetes cluster (e.g., Minikube, EKS, GKE)
- kubectl
- Helm 3
- Terraform
- Docker
## Helm Chart (Recommended)
**Quick install:**
```bash
export DOMAIN=your-domain.com
helm install my-twenty packages/twenty-docker/helm/twenty \
--namespace twentycrm --create-namespace --wait \
--set server.ingress.hosts[0].host=$DOMAIN \
--set server.ingress.hosts[0].paths[0].path=/ \
--set server.ingress.hosts[0].paths[0].pathType=Prefix \
--set server.ingress.tls[0].hosts[0]=$DOMAIN
```
See [QUICKSTART](../helm/twenty/QUICKSTART.md) and [chart README](../helm/twenty/README.md) for details.
## Setup Instructions
### Step 1: Clone the Repository
@@ -24,7 +40,7 @@ Clone the repository to your local machine:
``` bash
git clone https://github.com/twentyhq/twenty.git
cd twentycrm/packages/twenty-docker/k8s
cd twenty/packages/twenty-docker/k8s
```
### Step 2: Customize the Manifests and Terraform Files
@@ -59,7 +75,7 @@ cd twentycrm/packages/twenty-docker/k8s
## OR
### Step 3: Deploy with Kubernetes Manifests
### Step 3 (Alternative): Deploy with Kubernetes Manifests
1. Navigate to the Kubernetes manifests directory:
+29 -15
View File
@@ -164,6 +164,7 @@
"group": "CRM Automations",
"pages": [
"user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"user-guide/workflows/how-tos/crm-automations/formula-fields",
"user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -322,7 +323,7 @@
"user-guide/settings/capabilities/profile-settings",
"user-guide/settings/capabilities/experience-settings",
"user-guide/settings/capabilities/domains-settings",
"user-guide/settings/capabilities/releases-settings"
"user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -604,6 +605,7 @@
"group": "CRM Automations",
"pages": [
"l/fr/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/fr/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/fr/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/fr/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/fr/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -762,7 +764,7 @@
"l/fr/user-guide/settings/capabilities/profile-settings",
"l/fr/user-guide/settings/capabilities/experience-settings",
"l/fr/user-guide/settings/capabilities/domains-settings",
"l/fr/user-guide/settings/capabilities/releases-settings"
"l/fr/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -1044,6 +1046,7 @@
"group": "CRM Automations",
"pages": [
"l/ar/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/ar/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/ar/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/ar/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/ar/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -1202,7 +1205,7 @@
"l/ar/user-guide/settings/capabilities/profile-settings",
"l/ar/user-guide/settings/capabilities/experience-settings",
"l/ar/user-guide/settings/capabilities/domains-settings",
"l/ar/user-guide/settings/capabilities/releases-settings"
"l/ar/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -1484,6 +1487,7 @@
"group": "CRM Automations",
"pages": [
"l/cs/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/cs/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/cs/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/cs/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/cs/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -1642,7 +1646,7 @@
"l/cs/user-guide/settings/capabilities/profile-settings",
"l/cs/user-guide/settings/capabilities/experience-settings",
"l/cs/user-guide/settings/capabilities/domains-settings",
"l/cs/user-guide/settings/capabilities/releases-settings"
"l/cs/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -1924,6 +1928,7 @@
"group": "CRM Automations",
"pages": [
"l/de/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/de/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/de/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/de/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/de/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -2082,7 +2087,7 @@
"l/de/user-guide/settings/capabilities/profile-settings",
"l/de/user-guide/settings/capabilities/experience-settings",
"l/de/user-guide/settings/capabilities/domains-settings",
"l/de/user-guide/settings/capabilities/releases-settings"
"l/de/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -2364,6 +2369,7 @@
"group": "CRM Automations",
"pages": [
"l/es/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/es/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/es/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/es/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/es/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -2522,7 +2528,7 @@
"l/es/user-guide/settings/capabilities/profile-settings",
"l/es/user-guide/settings/capabilities/experience-settings",
"l/es/user-guide/settings/capabilities/domains-settings",
"l/es/user-guide/settings/capabilities/releases-settings"
"l/es/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -2804,6 +2810,7 @@
"group": "CRM Automations",
"pages": [
"l/it/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/it/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/it/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/it/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/it/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -2962,7 +2969,7 @@
"l/it/user-guide/settings/capabilities/profile-settings",
"l/it/user-guide/settings/capabilities/experience-settings",
"l/it/user-guide/settings/capabilities/domains-settings",
"l/it/user-guide/settings/capabilities/releases-settings"
"l/it/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -3244,6 +3251,7 @@
"group": "CRM Automations",
"pages": [
"l/ja/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/ja/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/ja/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/ja/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/ja/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -3402,7 +3410,7 @@
"l/ja/user-guide/settings/capabilities/profile-settings",
"l/ja/user-guide/settings/capabilities/experience-settings",
"l/ja/user-guide/settings/capabilities/domains-settings",
"l/ja/user-guide/settings/capabilities/releases-settings"
"l/ja/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -3684,6 +3692,7 @@
"group": "CRM Automations",
"pages": [
"l/ko/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/ko/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/ko/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/ko/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/ko/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -3842,7 +3851,7 @@
"l/ko/user-guide/settings/capabilities/profile-settings",
"l/ko/user-guide/settings/capabilities/experience-settings",
"l/ko/user-guide/settings/capabilities/domains-settings",
"l/ko/user-guide/settings/capabilities/releases-settings"
"l/ko/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -4124,6 +4133,7 @@
"group": "CRM Automations",
"pages": [
"l/pt/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/pt/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/pt/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/pt/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/pt/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -4282,7 +4292,7 @@
"l/pt/user-guide/settings/capabilities/profile-settings",
"l/pt/user-guide/settings/capabilities/experience-settings",
"l/pt/user-guide/settings/capabilities/domains-settings",
"l/pt/user-guide/settings/capabilities/releases-settings"
"l/pt/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -4564,6 +4574,7 @@
"group": "CRM Automations",
"pages": [
"l/ro/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/ro/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/ro/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/ro/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/ro/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -4722,7 +4733,7 @@
"l/ro/user-guide/settings/capabilities/profile-settings",
"l/ro/user-guide/settings/capabilities/experience-settings",
"l/ro/user-guide/settings/capabilities/domains-settings",
"l/ro/user-guide/settings/capabilities/releases-settings"
"l/ro/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -5004,6 +5015,7 @@
"group": "CRM Automations",
"pages": [
"l/ru/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/ru/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/ru/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/ru/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/ru/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -5162,7 +5174,7 @@
"l/ru/user-guide/settings/capabilities/profile-settings",
"l/ru/user-guide/settings/capabilities/experience-settings",
"l/ru/user-guide/settings/capabilities/domains-settings",
"l/ru/user-guide/settings/capabilities/releases-settings"
"l/ru/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -5444,6 +5456,7 @@
"group": "CRM Automations",
"pages": [
"l/tr/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/tr/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/tr/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/tr/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/tr/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -5602,7 +5615,7 @@
"l/tr/user-guide/settings/capabilities/profile-settings",
"l/tr/user-guide/settings/capabilities/experience-settings",
"l/tr/user-guide/settings/capabilities/domains-settings",
"l/tr/user-guide/settings/capabilities/releases-settings"
"l/tr/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -5884,6 +5897,7 @@
"group": "CRM Automations",
"pages": [
"l/zh/user-guide/workflows/how-tos/crm-automations/send-email-alerts-with-tasks-due",
"l/zh/user-guide/workflows/how-tos/crm-automations/notify-teammates-of-note-to-review",
"l/zh/user-guide/workflows/how-tos/crm-automations/display-number-of-emails-received",
"l/zh/user-guide/workflows/how-tos/crm-automations/formula-fields",
"l/zh/user-guide/workflows/how-tos/crm-automations/display-related-record-data",
@@ -6042,7 +6056,7 @@
"l/zh/user-guide/settings/capabilities/profile-settings",
"l/zh/user-guide/settings/capabilities/experience-settings",
"l/zh/user-guide/settings/capabilities/domains-settings",
"l/zh/user-guide/settings/capabilities/releases-settings"
"l/zh/user-guide/settings/capabilities/updates-settings"
]
},
{
@@ -6639,7 +6653,7 @@
},
{
"source": "/user-guide/settings/releases-settings",
"destination": "/user-guide/settings/capabilities/releases-settings"
"destination": "/user-guide/settings/capabilities/updates-settings"
},
{
"source": "/user-guide/settings/settings-faq",
Binary file not shown.

After

Width:  |  Height:  |  Size: 489 KiB

@@ -47,6 +47,16 @@ description: Understanding email integration features in Twenty.
## سلوك مزامنة البريد الإلكتروني
### Sync Rate
Twenty imports emails at approximately **400 messages per minute**. This rate is currently limited by Gmail API rate limiting (and applies similarly to other providers).
For reference:
* 1,000 emails → ~2.5 minutes
* 10,000 emails → ~25 minutes
* 50,000 emails → ~2 hours
### What Gets Synced
* **البريد الخارجي**: كافة رسائل البريد الإلكتروني مع جهات الاتصال خارج مؤسستك
@@ -60,12 +70,12 @@ description: Understanding email integration features in Twenty.
* **البريد الجماعي**: يتم استبعاد قوائم التوزيع والرسائل البريدية الجماعية
* **المجلدات المستبعدة**: يتم استبعاد المجلدات التي اخترت عدم مزامنتها (تم تكوينها تحت الإعدادات → الحسابات → البريد الإلكتروني)
### مزامنة المجلدات الانتقائية (ميزة مختبر)
### Selective Folder Sync
تحكم بما تم مزامنته من مجلدات البريد الإلكتروني مع Twenty:
1. تفعيل "مجلد الرسائل" في الإعدادات → الإصدارات → مختبر
2. تكوين المجلدات تحت الإعدادات → الحسابات → البريد الإلكتروني
1. Go to **Settings → Accounts** and select your connected email account
2. Configure folders under the Email section
3. اختر مجلدات معينة لتضمينها أو استبعادها (البريد الوارد، المرسل، الأرشيف، المجلدات المخصصة)
## استكشاف مشكلات مزامنة البريد الإلكتروني
@@ -25,7 +25,7 @@ description: اربط عدة حسابات بريد إلكتروني لمستخد
* **عرض البريد الإلكتروني**: اختر ما يمكن لزملائك رؤيته
* **الإنشاء التلقائي لجهات الاتصال**: تمكين/تعطيل لكل صندوق بريد
* **اختيار المجلدات**: اختر المجلدات التي تريد مزامنتها (ميزة مختبرية)
* **Folder selection**: Choose which folders to sync
## كيف تظهر رسائل البريد الإلكتروني
@@ -7,12 +7,12 @@ description: Troubleshooting missing emails on records.
### 1. Initial Sync Still in Progress
Email sync takes time, especially for large mailboxes.
Email sync takes time, especially for large mailboxes. Twenty imports emails at approximately **400 messages per minute** (limited by Gmail API rate limiting).
* **Calendar sync**: Completes in minutes
* **Email sync**: Can take several hours for large mailboxes
* **Email sync**: Depends on mailbox size (e.g., 10,000 emails ≈ 25 minutes, 50,000 emails ≈ 2 hours)
**Solution**: Wait up to a few hours for the initial import to complete.
**Solution**: Wait for the initial import to complete. You can estimate timing based on your mailbox size.
### ٢. Contact Doesn't Exist in Twenty
@@ -11,11 +11,9 @@ description: تحكّم في أي رسائل بريد إلكتروني تُست
تحكم بما تم مزامنته من مجلدات البريد الإلكتروني مع Twenty:
1. اذهب إلى **الإعدادات → الإصدارات → المختبر**
2. فعِّل **مجلد الرسائل**
3. العودة إلى **الإعدادات → الحسابات**
4. اختر حساب البريد الإلكتروني المتصل لديك
5. اختر المجلدات التي تريد مزامنتها:
1. اذهب إلى **الإعدادات → الحسابات**
2. اختر حساب البريد الإلكتروني المتصل لديك
3. اختر المجلدات التي تريد مزامنتها:
| مجلد | الوصف |
| --------------------- | --------------------------------- |
@@ -34,11 +34,10 @@ image: /images/user-guide/emails/emails_header.png
بالنسبة لمزودي البريد الإلكتروني والتقويم الآخرين:
1. انتقل إلى **الإعدادات → الإصدارات → المعمل** لتفعيل الميزة
2. العودة إلى **الإعدادات → الحسابات**
3. قم بتكوين إعدادات SMTP للبريد الإلكتروني
4. قم بتكوين إعدادات CalDAV للتقويم
5. اختبر الاتصال
1. اذهب إلى **الإعدادات → الحسابات**
2. قم بتكوين إعدادات SMTP للبريد الإلكتروني
3. قم بتكوين إعدادات CalDAV للتقويم
4. اختبر الاتصال
### صناديق بريد متعددة
@@ -69,13 +68,12 @@ image: /images/user-guide/emails/emails_header.png
<Note>When enabled, contacts are automatically linked to their Company records based on their email domain. If the company doesn't exist yet, Twenty creates it for you.</Note>
### التحكم بالرسائل التي تتم مزامنتها من خلال اختيار مجلد الرسائل (ميزة معمل)
### Control which emails get synced with Message Folder Selection
تحكم بما تم مزامنته من مجلدات البريد الإلكتروني مع Twenty:
1. انتقل إلى **الإعدادات → الإصدارات → المعمل** وفعل **مجلد الرسائل**
2. العودة إلى **الإعدادات → الحسابات** وحدد حساب البريد الإلكتروني المتصل.
3. اختر المجلدات التي تريد مزامنتها:
1. Go to **Settings → Accounts** and select your connected email account
2. اختر المجلدات التي تريد مزامنتها:
* **البريد الوارد**: رسائل البريد الأولية الواردة
* **بريد مرسل**: رسائل البريد الصادرة التي قمت بإرسالها
* **مجلدات مخصصة**: أي مجلدات محددة تريد تضمينها
@@ -123,7 +121,7 @@ image: /images/user-guide/emails/emails_header.png
**التحديثات كل 5 دقائق**: تتم مزامنة البيانات البريدية والتقويمية تلقائيًا كل 5 دقائق بعد الاستيراد الأولي.
<Note>
**Initial sync timing**: Calendar sync completes quickly (usually within minutes), while email sync takes longer for large mailboxes—up to a few hours depending on volume. Don't worry if you see contacts from calendar events appearing before your email contacts; this is normal behavior.
**Initial sync timing**: Calendar sync completes quickly (usually within minutes), while email sync takes longer for large mailboxes. Twenty imports emails at approximately **400 messages per minute** (limited by Gmail API rate limiting), so a mailbox with 10,000 emails takes about 25 minutes. Don't worry if you see contacts from calendar events appearing before your email contacts; this is normal behavior.
</Note>
## الخطوات التالية
@@ -8,6 +8,10 @@ image: /images/user-guide/reporting/pie-chart.png
<img src="/images/user-guide/reporting/pie-chart.png" alt="لوحات القيادة" />
</Frame>
<Note>
Dashboards are currently in beta. Activate them under **Settings → Updates → Early Access**.
</Note>
## فهم لوحات المعلومات
توفّر لوحات المعلومات في Twenty طريقة مرئية لتتبّع مقاييس الأداء الأساسية لديك واستخلاص الرؤى من بيانات إدارة علاقات العملاء (CRM) لديك.
@@ -1,122 +1,122 @@
---
title: Fix Import Errors
description: Complete troubleshooting guide for resolving CSV import errors.
title: إصلاح أخطاء الاستيراد
description: دليل شامل لاستكشاف أخطاء استيراد CSV وإصلاحها.
---
## نظرة عامة
Import not working? This guide helps you identify and fix common import errors step by step.
هل تواجه مشكلة في الاستيراد؟ يساعدك هذا الدليل على تحديد أخطاء الاستيراد الشائعة وإصلاحها خطوة بخطوة.
## How Import Validation Works
## كيف تعمل عملية التحقّق من الاستيراد
After uploading your file and mapping columns, Twenty validates your data:
بعد رفع ملفك وتعيين الأعمدة، تتحقّق Twenty من بياناتك:
1. **Validation runs** — Twenty checks each row for errors
2. **Errors are highlighted** — problematic rows appear in **yellow**
3. **You can fix in-place** — edit cells directly in the import UI
4. **Or remove rows** — skip problematic records entirely
1. **تُجرى عملية التحقّق** — تتحقّق Twenty من كل صف بحثًا عن الأخطاء
2. **تمييز الأخطاء** — تظهر الصفوف ذات المشكلات باللون **الأصفر**
3. **يمكنك الإصلاح مباشرةً** — حرّر الخلايا مباشرةً في واجهة الاستيراد
4. **أو إزالة الصفوف** — تخطَّ السجلات التي بها مشكلات تمامًا
<Note>**Fix errors in the UI.** You don't need to go back to your spreadsheet. Edit cells directly during import to save time.</Note>
<Note>**أصلِح الأخطاء في الواجهة.** لست مضطرًا للعودة إلى جدول البيانات الخاص بك. حرّر الخلايا مباشرة أثناء الاستيراد لتوفير الوقت.</Note>
## Step-by-Step Troubleshooting
## استكشاف الأخطاء وإصلاحها خطوة بخطوة
### Step 1: Identify the Error Type
### الخطوة 1: تحديد نوع الخطأ
Click on a highlighted row to see the specific error message. Common error types:
انقر على صف مميّز للاطلاع على رسالة الخطأ المحددة. أنواع الأخطاء الشائعة:
| Error Message | What It Means |
| --------------------------------------------------------------------- | ------------------------------------------------------------ |
| Duplicate values highlighted in yellow | Value already exists in Twenty or appears twice in your file |
| `{field} is not a valid {type}` (hover on yellow cell) | Data doesn't match expected format |
| Required field highlighted | A required field is empty |
| `Can't connect to {object}. No unique record found...` (import fails) | Referenced record doesn't exist |
| `Too many records. Up to 10000 allowed` (upload blocked) | File has more than 10,000 records |
| رسالة الخطأ | ماذا يعني ذلك |
| ----------------------------------------------------------------------- | ---------------------------------------------------- |
| تم تمييز القيم المكرّرة باللون الأصفر | القيمة موجودة مسبقًا في Twenty أو تظهر مرتين في ملفك |
| `{field} is not a valid {type}` (مرّر المؤشر فوق الخلية الصفراء) | البيانات لا تطابق التنسيق المتوقع |
| تم تمييز الحقل المطلوب | الحقل المطلوب فارغ |
| `Can't connect to {object}. No unique record found...` (يفشل الاستيراد) | السجل المشار إليه غير موجود |
| `Too many records. Up to 10000 allowed` (تم حظر التحميل) | يحتوي الملف على أكثر من 10,000 سجل |
### Step 2: Fix the Error
### الخطوة 2: إصلاح الخطأ
Follow the specific instructions below for each error type.
اتّبع الإرشادات المحددة أدناه لكل نوع من الأخطاء.
---
## Error: Duplicate Value
## خطأ: قيمة مكرّرة
### ما ستراه
Rows with duplicate values are **highlighted in yellow** in the import UI before the import starts.
تُميَّز الصفوف ذات القيم المكرّرة باللون **الأصفر** في واجهة الاستيراد قبل بدء الاستيراد.
### What It Means
### ماذا يعني ذلك
A unique field (email, domain) either:
حقل فريد (البريد الإلكتروني، النطاق) إمّا:
* Already exists in Twenty
* Appears twice in your file
* موجود مسبقًا في Twenty
* يظهر مرتين في ملفك
### How to Fix
### كيفية الإصلاح
**Option 1: Edit the duplicate value**
**الخيار 1: تعديل القيمة المكرّرة**
1. Click the cell with the error
2. Change to a unique value
3. Continue with import
1. انقر فوق الخلية التي تحتوي على الخطأ
2. غيّرها إلى قيمة فريدة
3. تابع الاستيراد
**Option 2: Remove the duplicate row**
**الخيار 2: إزالة الصف المكرّر**
1. Click the X next to the row
2. The row will be skipped during import
1. انقر الرمز X بجوار الصف
2. سيتم تخطّي الصف أثناء الاستيراد
**Option 3: Let Twenty update the existing record**
**الخيار 3: دع Twenty تحدّث السجل الموجود**
1. Ensure your file includes a unique identifier (`email`, `domain`, or `id`)
2. Map the unique identifier field
3. Twenty will update the existing record instead of creating a duplicate
1. تأكّد من أن ملفك يتضمن معرّفًا فريدًا (`email`، `domain`، أو `id`)
2. قم بتعيين حقل المعرّف الفريد
3. ستقوم Twenty بتحديث السجل الموجود بدلًا من إنشاء نسخة مكرّرة
<Note>
**You can update unique fields too.**
**يمكنك تحديث الحقول الفريدة أيضًا.**
* If you keep the `id` but change the `email` → the email will be updated
* If you keep the `email` but change the `id` → the id will be updated
* إذا أبقيت على `id` لكن غيّرت `email` → فسيتم تحديث البريد الإلكتروني
* إذا أبقيت على `email` لكن غيّرت `id` → فسيتم تحديث المعرّف
As long as one unique identifier matches, Twenty updates the record.
طالما أن أحد المعرّفات الفريدة يطابق، تقوم Twenty بتحديث السجل.
</Note>
### How to Prevent This Error
### كيفية منع هذا الخطأ
Before importing:
قبل الاستيراد:
1. Sort your spreadsheet by the unique field
2. Remove duplicate rows
3. Check if records already exist in Twenty
1. رتّب جدول البيانات حسب الحقل الفريد
2. أزل الصفوف المكرّرة
3. تحقّق مما إذا كانت السجلات موجودة مسبقًا في Twenty
<Warning>
**Soft-deleted records count toward uniqueness.**
**السجلات المحذوفة حذفًا ناعمًا تُحتسب ضمن التفرد.**
Check Command Menu → See deleted records. Records there still enforce uniqueness. Permanently delete them or restore and update.
تحقّق من قائمة الأوامر → اعرض السجلات المحذوفة. السجلات هناك ما تزال تفرض شرط التفرد. احذفها نهائيًا أو استعدها وقم بتحديثها.
</Warning>
For more details: [Uniqueness Constraints](/l/ar/user-guide/data-migration/capabilities/uniqueness-constraints)
لمزيد من التفاصيل: [قيود التفرد](/l/ar/user-guide/data-migration/capabilities/uniqueness-constraints)
---
## Error: Invalid Format
## خطأ: تنسيق غير صالح
### ما ستراه
The cell value is highlighted in yellow. Hover over it to see the error message:
تم تمييز قيمة الخلية باللون الأصفر. مرّر المؤشر فوقها للاطلاع على رسالة الخطأ:
```
{field name} is not a valid {field type}
```
### What It Means
### ماذا يعني ذلك
The data doesn't match the expected format for that field type.
لا تطابق البيانات التنسيق المتوقع لذلك النوع من الحقول.
### How to Fix — By Field Type
### كيفية الإصلاح — حسب نوع الحقل
#### البريد الإلكتروني
**Problem:** Invalid email format
**Solution:** Use format `name@domain.com`
**المشكلة:** تنسيق بريد إلكتروني غير صالح
**الحل:** استخدم التنسيق `name@domain.com`
```
❌ john.smith@
@@ -126,8 +126,8 @@ The data doesn't match the expected format for that field type.
#### النطاق
**Problem:** Inconsistent format may cause duplicates
**Solution:** Use `https://domain.com` format (recommended)
**المشكلة:** قد يتسبب عدم اتساق التنسيق في حدوث تكرارات
**الحل:** استخدم تنسيق `https://domain.com` (موصى به)
```
⚠️ acme.com (valid, but not recommended)
@@ -135,12 +135,12 @@ The data doesn't match the expected format for that field type.
✅ https://acme.com (recommended)
```
<Note>All formats are valid, but `https://domain.com` is recommended because it matches the format used by email/calendar sync. Using other formats may create duplicate companies.</Note>
<Note>جميع التنسيقات صالحة، لكن يُوصى بـ `https://domain.com` لأنه يطابق التنسيق المستخدم في مزامنة البريد الإلكتروني/التقويم. قد يؤدي استخدام تنسيقات أخرى إلى إنشاء شركات مكرّرة.</Note>
#### تاريخ
**Problem:** Unrecognized date format
**Solution:** Use consistent format throughout file
**المشكلة:** تنسيق تاريخ غير معروف
**الحل:** استخدم تنسيقًا متّسقًا في جميع أنحاء الملف
```
✓ 2024-03-15 (YYYY-MM-DD - recommended)
@@ -150,10 +150,10 @@ The data doesn't match the expected format for that field type.
#### هاتف
**Problem:** Missing required columns
**Solution:** Include all phone columns
**المشكلة:** أعمدة مطلوبة مفقودة
**الحل:** تضمين جميع أعمدة الهاتف
| Column | مثال |
| العمود | مثال |
| --------------------------------------- | ------------ |
| **Phones / Primary Phone Number** | `4159095555` |
| **Phones / Primary Phone Country Code** | `US` |
@@ -161,8 +161,8 @@ The data doesn't match the expected format for that field type.
#### قيمة منطقية
**Problem:** Wrong boolean value
**Solution:** Use uppercase `TRUE` or `FALSE`
**المشكلة:** قيمة منطقية خاطئة
**الحل:** استخدم `TRUE` أو `FALSE` بحروف كبيرة
```
❌ true
@@ -172,17 +172,17 @@ The data doesn't match the expected format for that field type.
✓ FALSE
```
#### Select / Multi-Select
#### اختيار / اختيار متعدد
**Problem:** Value doesn't match existing options
**Solution:** Use **API names**, not display labels
**المشكلة:** لا تطابق القيمة الخيارات الموجودة
**الحل:** استخدم **أسماء واجهة برمجة التطبيقات (API)**، وليس تسميات العرض
How to find API names:
كيفية العثور على أسماء واجهة برمجة التطبيقات:
1. Go to **Settings → Data Model**
2. Select the object and field
3. Enable **Advanced mode** (toggle at bottom right)
4. Use the API name (e.g., `OPTION_1`, not "Option 1")
1. اذهب إلى **الإعدادات → نموذج البيانات**
2. اختر الكائن والحقل
3. فعّل **الوضع المتقدم** (زر التبديل في أسفل اليمين)
4. استخدم اسم واجهة برمجة التطبيقات (على سبيل المثال، `OPTION_1`، وليس "Option 1")
```
❌ High Priority
@@ -191,18 +191,18 @@ How to find API names:
#### العملة
**Problem:** Missing amount or currency code
**Solution:** Fill both columns
**المشكلة:** المبلغ أو رمز العملة مفقود
**الحل:** املأ كلا العمودين
| Column | مثال |
| --------------------- | --------- |
| **Amount / Amount** | `1234.56` |
| **Amount / Currency** | `USD` |
| العمود | مثال |
| ------------------- | --------- |
| **المبلغ / المبلغ** | `1234.56` |
| **المبلغ / العملة** | `USD` |
#### رقم
**Problem:** Non-numeric characters
**Solution:** Numbers only, period for decimals
**المشكلة:** أحرف غير رقمية
**الحل:** أرقام فقط، ونقطة للفواصل العشرية
```
❌ $1,234.56
@@ -210,221 +210,221 @@ How to find API names:
✓ 1234.56
```
For complete format reference: [Field Mapping](/l/ar/user-guide/data-migration/capabilities/field-mapping)
للاطلاع على مرجع التنسيقات الكامل: [مرجع تعيين الحقول](/l/ar/user-guide/data-migration/capabilities/field-mapping)
---
## Error: Required Field Missing
## خطأ: حقل مطلوب مفقود
### ما ستراه
The row is highlighted in yellow with the required field cell marked.
تم تمييز الصف باللون الأصفر مع وضع علامة على خلية الحقل المطلوب.
### What It Means
### ماذا يعني ذلك
A required field is empty for this row.
الحقل المطلوب فارغ لهذا الصف.
### How to Fix
### كيفية الإصلاح
**Option 1: Enter a value**
**الخيار 1: إدخال قيمة**
1. Click the empty cell
2. Enter a value
3. Continue with import
1. انقر فوق الخلية الفارغة
2. أدخل قيمة
3. تابع الاستيراد
**Option 2: Remove the row**
**الخيار 2: إزالة الصف**
1. If you don't have the data, click X to skip the row
1. إذا لم تكن لديك البيانات، انقر X لتخطّي الصف
### How to Prevent This Error
### كيفية منع هذا الخطأ
Before importing, identify required fields:
قبل الاستيراد، حدّد الحقول المطلوبة:
1. Go to **Settings → Data Model**
2. Select your object
3. Check which fields are marked as required
1. اذهب إلى **الإعدادات → نموذج البيانات**
2. اختر الكائن الخاص بك
3. تحقّق من الحقول المُعلمة كمطلوبة
---
## Error: Relation Not Found
## خطأ: العلاقة غير موجودة
### ما ستراه
This error appears **after the import starts** — the import fails with a message like:
يظهر هذا الخطأ **بعد بدء الاستيراد** — يفشل الاستيراد برسالة مثل:
```
Can't connect to company. No unique record found with condition: id = 7776ee49-f608-4a77-8cc8-6fe96ae1e43f
```
This means there is no Company in Twenty with that specific identifier.
هذا يعني أنه لا توجد شركة في Twenty بذلك المعرّف المحدّد.
<Note>Unlike other errors, this one is not caught during the data review step. The import will start and then fail when it encounters the missing relation.</Note>
<Note>على عكس الأخطاء الأخرى، لا يُلتقط هذا الخطأ أثناء خطوة مراجعة البيانات. سيبدأ الاستيراد ثم يفشل عند مواجهة العلاقة المفقودة.</Note>
### What It Means
### ماذا يعني ذلك
You're trying to link to a record that doesn't exist in Twenty.
تحاول ربط سجل غير موجود في Twenty.
### How to Fix
### كيفية الإصلاح
**Option 1: Import parent records first**
**الخيار 1: استيراد سجلات الأصل أولًا**
1. Cancel the current import
2. Import the parent records (e.g., Companies)
3. Then import the child records (e.g., People)
1. ألغِ الاستيراد الحالي
2. استورد سجلات الأصل (مثلًا، الشركات)
3. ثم استورد سجلات التابع (مثلًا، الأشخاص)
**Option 2: Fix the reference value**
**الخيار 2: أصلِح قيمة المرجع**
1. Check the reference value in your file
2. Ensure it exactly matches an existing record
3. Verify format: domains should be `https://domain.com`
1. تحقّق من قيمة المرجع في ملفك
2. تأكّد من أنه يطابق سجلًا موجودًا تمامًا
3. تحقّق من التنسيق: يجب أن تكون النطاقات بصيغة `https://domain.com`
**Option 3: Remove the relation**
**الخيار 3: إزالة العلاقة**
1. Clear the cell to import without the relation
2. Add the relation manually later
1. امسح الخلية للاستيراد دون العلاقة
2. أضِف العلاقة يدويًا لاحقًا
### How to Prevent This Error
### كيفية منع هذا الخطأ
1. **Import in the correct order:**
* Companies first
* People second (with company references)
* Opportunities third
1. **استورد بالترتيب الصحيح:**
* الشركات أولًا
* الأشخاص ثانيًا (مع مراجع الشركة)
* الفرص ثالثًا
2. **Verify reference values:**
* Export parent records to get exact identifiers
* Use domain format `https://domain.com`
* Check for typos and case sensitivity
2. **تحقّق من قيم المراجع:**
* صدّر سجلات الأصل للحصول على معرّفات دقيقة
* استخدم تنسيق النطاق `https://domain.com`
* تحقّق من الأخطاء الإملائية وحساسية حالة الأحرف
<Warning>
**Import will fail if a reference is made to a non-existent record.**
**سيفشل الاستيراد إذا تمت الإشارة إلى سجل غير موجود.**
Always import parent objects before child objects.
استورد دائمًا كائنات الأصل قبل كائنات التابع.
</Warning>
For more details: [Import Relations](/l/ar/user-guide/data-migration/capabilities/import-relations)
لمزيد من التفاصيل: [استيراد العلاقات](/l/ar/user-guide/data-migration/capabilities/import-relations)
---
## Error: File Too Large
## خطأ: ملف كبير جدًا
### ما ستراه
This error appears **when uploading your file** — the upload is blocked entirely:
يظهر هذا الخطأ **عند رفع ملفك** — يتم حظر التحميل بالكامل:
```
Too many records. Up to 10000 allowed
```
You won't be able to proceed to the data review step until you reduce the file size.
لن تتمكّن من الانتقال إلى خطوة مراجعة البيانات حتى تقلّل حجم الملف.
### What It Means
### ماذا يعني ذلك
Your file has more than 10,000 records.
يحتوي ملفك على أكثر من 10,000 سجل.
### How to Fix
### كيفية الإصلاح
**Option 1: Split into multiple files**
**الخيار 1: التقسيم إلى عدة ملفات**
1. Divide your data into files of 10,000 records or fewer
2. Import each file separately
3. Maintain import order (Companies before People)
1. قسّم بياناتك إلى ملفات تحتوي على 10,000 سجل أو أقل
2. استورد كل ملف على حدة
3. حافظ على ترتيب الاستيراد (الشركات قبل الأشخاص)
**Option 2: Use API import**
For very large datasets, use the API which has no record limit.
See: [How to Import Data via API](/l/ar/user-guide/data-migration/how-tos/import-data-via-api)
**الخيار 2: استخدم الاستيراد عبر واجهة برمجة التطبيقات (API)**
بالنسبة لمجموعات البيانات الكبيرة جدًا، استخدم واجهة برمجة التطبيقات التي لا تحتوي على حد لعدد السجلات.
راجع: [كيفية استيراد البيانات عبر واجهة برمجة التطبيقات (API)](/l/ar/user-guide/data-migration/how-tos/import-data-via-api)
---
## Error: Field Not Recognized
## خطأ: لم يتم التعرّف على الحقل
### What It Means
### ماذا يعني ذلك
A column in your file can't be mapped because the field doesn't exist in Twenty.
لا يمكن تعيين عمود في ملفك لأن الحقل غير موجود في Twenty.
### How to Fix
### كيفية الإصلاح
1. Go to **Settings → Data Model**
2. Select the object you're importing
3. Click **+ Add field**
4. Create the custom field with the appropriate type
5. Re-upload your file
1. اذهب إلى **الإعدادات → نموذج البيانات**
2. اختر الكائن الذي تستورده
3. انقر **+ إضافة حقل**
4. أنشئ الحقل المخصّص بالنوع المناسب
5. أعد رفع ملفك
<Note>The CSV import creates records, not fields. All fields must exist before importing.</Note>
<Note>يُنشئ استيراد CSV سجلات، وليس حقولًا. يجب أن تكون جميع الحقول موجودة قبل الاستيراد.</Note>
---
## Error: User Relation Empty
## خطأ: علاقة المستخدم فارغة
### What It Means
### ماذا يعني ذلك
You're trying to assign a record to a user (Owner, Assignee) but the relation isn't being mapped.
تحاول إسناد سجل إلى مستخدم (المالك، المعيَّن) لكن العلاقة لا يتم تعيينها.
### Common Causes
### أسباب شائعة
1. **User hasn't accepted their invitation** — the user doesn't exist in Twenty yet
2. **Using user ID from old system** — Twenty can't match IDs from another system
3. **Wrong email format** — the email doesn't match the user's Twenty account
1. **لم يقبل المستخدم دعوته** — المستخدم غير موجود في Twenty بعد
2. **استخدام معرّف مستخدم من نظام قديم** — لا تستطيع Twenty مطابقة المعرّفات من نظام آخر
3. **تنسيق بريد إلكتروني خاطئ** — البريد الإلكتروني لا يطابق حساب المستخدم في Twenty
### How to Fix
### كيفية الإصلاح
1. Ensure all users have **accepted their invitation** to your Twenty workspace
2. Use the user's **email address** (not their name or old system ID)
3. Use the same email they used to join Twenty
1. تأكّد من أن جميع المستخدمين قد **قبلوا دعوتهم** إلى مساحة عمل Twenty الخاصة بك
2. استخدم **عنوان البريد الإلكتروني** الخاص بالمستخدم (وليس اسمه أو معرّف النظام القديم)
3. استخدم البريد الإلكتروني نفسه الذي استخدموه للانضمام إلى Twenty
<Warning>
**Users must accept invitations before importing.**
**يجب على المستخدمين قبول الدعوات قبل الاستيراد.**
If a user hasn't accepted their invitation, records referencing them will have empty user relations.
إذا لم يقبل المستخدم دعوته، فستكون علاقات المستخدم فارغة في السجلات التي تشير إليه.
</Warning>
---
## Pre-Import Checklist
## قائمة ما قبل الاستيراد
Avoid errors by checking these before importing:
تجنّب الأخطاء من خلال التحقّق مما يلي قبل الاستيراد:
### File Requirements
### متطلبات الملف
<Check>File is CSV, XLSX, or XLS format</Check>
<Check>File has fewer than 10,000 records</Check>
<Check>File uses UTF-8 encoding</Check>
<Check>الملف بتنسيق CSV أو XLSX أو XLS</Check>
<Check>يحتوي الملف على أقل من 10,000 سجل</Check>
<Check>يستخدم الملف ترميز UTF-8</Check>
### Data Quality
### جودة البيانات
<Check>No duplicate emails (for People)</Check>
<Check>No duplicate domains (for Companies)</Check>
<Check>All dates use consistent format</Check>
<Check>All domains use `https://domain.com` format</Check>
<Check>لا توجد رسائل بريد إلكتروني مكرّرة (للأشخاص)</Check>
<Check>لا توجد نطاقات مكرّرة (للشركات)</Check>
<Check>جميع التواريخ تستخدم تنسيقًا متّسقًا</Check>
<Check>جميع النطاقات تستخدم تنسيق `https://domain.com`</Check>
### Field Formats
### تنسيقات الحقول
<Check>Boolean fields use `TRUE` or `FALSE` (uppercase)</Check>
<Check>Select fields use API names, not display labels</Check>
<Check>Phone fields have all required columns</Check>
<Check>Currency fields have both Amount and Currency Code</Check>
<Check>الحقول المنطقية تستخدم `TRUE` أو `FALSE` (أحرف كبيرة)</Check>
<Check>حقول الاختيار تستخدم أسماء واجهة برمجة التطبيقات (API)، وليس تسميات العرض</Check>
<Check>حقول الهاتف تحتوي على جميع الأعمدة المطلوبة</Check>
<Check>حقول العملة تتضمن كلًا من المبلغ ورمز العملة</Check>
### العلاقات
<Check>Parent records imported before child records</Check>
<Check>Relation columns reference existing records</Check>
<Check>Domain format matches Twenty's format exactly</Check>
<Check>تم استيراد سجلات الأصل قبل سجلات التابع</Check>
<Check>أعمدة العلاقات تشير إلى سجلات موجودة</Check>
<Check>تنسيق النطاق يطابق تنسيق Twenty تمامًا</Check>
### نموذج البيانات
<Check>All custom fields exist in Settings → Data Model</Check>
<Check>Select options exist before importing</Check>
<Check>جميع الحقول المخصّصة موجودة في الإعدادات → نموذج البيانات</Check>
<Check>خيارات الاختيار موجودة قبل الاستيراد</Check>
---
## Still Having Issues?
## هل لا تزال تواجه مشكلات؟
If you've tried the above solutions:
إذا كنت قد جرّبت الحلول أعلاه:
1. **Download the sample file** — see the exact format Twenty expects
2. **Export existing records** — compare your file to working data
3. **Test with a small batch** — try 5-10 rows first
4. **Check the reference articles:**
* [Field Mapping](/l/ar/user-guide/data-migration/capabilities/field-mapping)
* [Uniqueness Constraints](/l/ar/user-guide/data-migration/capabilities/uniqueness-constraints)
* [Import Relations](/l/ar/user-guide/data-migration/capabilities/import-relations)
* [Error Handling](/l/ar/user-guide/data-migration/capabilities/error-handling)
1. **نزّل ملف العيّنة** — اطّلع على التنسيق الدقيق الذي تتوقعه Twenty
2. **صدّر السجلات الموجودة** — قارن ملفك بالبيانات التي تعمل بشكل صحيح
3. **اختبر بدفعة صغيرة** — جرّب 5-10 صفوف أولًا
4. **اطّلع على مقالات المرجع:**
* [مرجع تعيين الحقول](/l/ar/user-guide/data-migration/capabilities/field-mapping)
* [قيود التفرد](/l/ar/user-guide/data-migration/capabilities/uniqueness-constraints)
* [كيفية استيراد العلاقات](/l/ar/user-guide/data-migration/capabilities/import-relations)
* [التعامل مع الأخطاء](/l/ar/user-guide/data-migration/capabilities/error-handling)
@@ -1,103 +1,103 @@
---
title: Import Relations Between Objects via CSV
description: Complete step-by-step guide to linking records during CSV import.
title: استيراد العلاقات بين الكائنات عبر CSV
description: دليل كامل خطوة بخطوة لربط السجلات أثناء استيراد CSV.
---
## نظرة عامة
This guide walks you through importing relations between objects—for example, linking People to Companies, or Opportunities to People.
يأخذك هذا الدليل خلال استيراد العلاقات بين الكائنات—على سبيل المثال، ربط الأشخاص بالشركات، أو الفرص بالأشخاص.
<Note>**What can be imported:** Only one-to-many relations pointing to a single object type. Relations pointing to multiple object types (like Notes linking to People AND Companies) are not yet supported for import.</Note>
<Note>**ما الذي يمكن استيراده:** العلاقات من واحد إلى متعدد التي تشير إلى نوع كائن واحد فقط. العلاقات التي تشير إلى أنواع كائنات متعددة (مثل ملاحظات مرتبطة بالأشخاص والشركات معًا) غير مدعومة للاستيراد بعد.</Note>
## Understanding Relations
## فهم العلاقات
### What is a "One-to-Many" Relation?
### ما هي علاقة "واحد إلى متعدد"؟
In a one-to-many relation:
في علاقة واحد إلى متعدد:
* **One** Company has **many** People (employees)
* **One** Company has **many** Opportunities
* **One** Person has **many** Tasks
* **شركة واحدة** لديها **العديد** من الأشخاص (الموظفين)
* **شركة واحدة** لديها **العديد** من الفرص
* **شخص واحد** لديه **العديد** من المهام
The "one" side is the **parent**. The "many" side is the **child**.
جانب "الواحد" هو **الأصل**. جانب "المتعدد" هو **التابع**.
### Common Relations in Twenty
### العلاقات الشائعة في Twenty
| علاقة | "One" Side (Parent) | "Many" Side (Child) |
| ------------------------- | ------------------- | ------------------- |
| Companies → People | الشركة | الأشخاص |
| Companies → Opportunities | الشركة | الفرص |
| People → Tasks | شخص | المهام |
| People → Notes | شخص | الملاحظات |
| علاقة | جانب "الواحد" (الأصل) | جانب "المتعدد" (التابع) |
| ------------------- | --------------------- | ----------------------- |
| الشركات → الأشخاص | الشركة | الأشخاص |
| الشركات → الفرص | الشركة | الفرص |
| الأشخاص → المهام | شخص | المهام |
| الأشخاص → الملاحظات | شخص | الملاحظات |
## Step 1: Identify the "One" and "Many" Sides
## الخطوة 1: تحديد جانبي "الواحد" و"المتعدد"
Before importing, determine which object is the parent and which is the child.
قبل الاستيراد، حدّد أي الكائنات هو الأصل وأيها التابع.
**Ask yourself:** "Does ONE [Object A] have MANY [Object B]?"
**اسأل نفسك:** "هل لدى كائن واحد من [Object A] العديد من [Object B]؟"
* One Company → Many People ✓ (Company is parent)
* One Person → Many Companies ✗ (This is wrong—a person belongs to one company)
* شركة واحدة → العديد من الأشخاص ✓ (الشركة هي الأصل)
* شخص واحد → العديد من الشركات ✗ (هذا خطأ — الشخص ينتمي إلى شركة واحدة)
## Step 2: Import the Parent Records First
## الخطوة 2: استيراد سجلات الأصل أولًا
The parent ("one" side) must exist in Twenty before you can reference it.
يجب أن يكون الأصل (جانب "الواحد") موجودًا في Twenty قبل أن تتمكّن من الإشارة إليه.
**Import order:**
**ترتيب الاستيراد:**
1. **Companies** first (no dependencies)
2. **People** second (link to Companies)
3. **Opportunities** third (link to Companies and/or People)
4. **Tasks/Notes** (link to any of the above)
1. **الشركات** أولًا (من دون تبعيات)
2. **الأشخاص** ثانيًا (مرتبطون بالشركات)
3. **الفرص** ثالثًا (مرتبطة بالشركات و/أو الأشخاص)
4. **المهام/الملاحظات** (مرتبطة بأي مما سبق)
<Warning>
**If the parent record doesn't exist, the import will fail.**
**إذا كان سجل الأصل غير موجود، فسيفشل الاستيراد.**
Always verify that Companies are imported before importing People with company references.
تحقّق دائمًا من استيراد الشركات قبل استيراد الأشخاص الذين لديهم مراجع للشركات.
</Warning>
## Step 3: Note the Parent's Unique Identifier
## الخطوة 3: تدوين المعرّف الفريد للأصل
You need to reference the parent record using a **unique identifier**. Available options:
تحتاج إلى الإشارة إلى سجل الأصل باستخدام **مُعرّف فريد**. الخيارات المتاحة:
| Parent Object | Available Unique Identifiers |
| --------------------- | --------------------------------------------------------------- |
| **الشركات** | `id` (UUID), `domain` (recommended), or any custom unique field |
| **People** | `id` (UUID), `email`, or any custom unique field |
| **أعضاء مساحة العمل** | `id` (UUID), `email` (not name) |
| **كائنات مخصصة** | `id` (UUID), or any field marked as unique |
| كائن الأصل | المُعرّفات الفريدة المتاحة |
| --------------------- | ---------------------------------------------------- |
| **الشركات** | `id` (UUID)، `domain` (موصى به)، أو أي حقل فريد مخصص |
| **الأشخاص** | `id` (UUID)، `email`، أو أي حقل فريد مخصص |
| **أعضاء مساحة العمل** | `id` (UUID)، `email` (ليس الاسم) |
| **كائنات مخصصة** | `id` (UUID)، أو أي حقل مميز كفريد |
<Note>**Recommended:** Use `domain` for Companies and `email` for People. These are human-readable and easy to verify in your spreadsheet.</Note>
<Note>**موصى به:** استخدم `domain` للشركات و`email` للأشخاص. هذه مقروءة للبشر وسهلة التحقّق منها في جدول البيانات الخاص بك.</Note>
### Finding the Identifier
### العثور على المعرّف
If you need the `id`:
إذا كنت تحتاج إلى `id`:
1. Export the parent records from Twenty
2. The export includes the `id` column
3. Use these IDs in your child records file
1. صدّر سجلات الأصل من Twenty
2. يتضمن التصدير عمود `id`
3. استخدم هذه المعرّفات في ملف سجلات التابع
## Step 4: Verify the Relation Field Exists
## الخطوة 4: التحقّق من وجود حقل العلاقة
Before importing, ensure the relation field exists between your objects.
قبل الاستيراد، تأكّد من وجود حقل العلاقة بين كائناتك.
**To check or create:**
**للتحقّق أو الإنشاء:**
1. Go to **Settings → Data Model**
2. Select your child object (e.g., People)
3. Look for a relation field pointing to the parent (e.g., Company)
4. If it doesn't exist, create it:
* Click **+ Add field**
* Select **Relation** type
* Choose the parent object
1. اذهب إلى **الإعدادات → نموذج البيانات**
2. اختر كائن التابع الخاص بك (مثلًا، الأشخاص)
3. ابحث عن حقل علاقة يشير إلى الأصل (مثلًا، الشركة)
4. إذا لم يكن موجودًا، فقم بإنشائه:
* انقر **+ إضافة حقل**
* اختر نوع **العلاقة**
* اختر كائن الأصل
## Step 5: Prepare Your CSV File
## الخطوة 5: جهّز ملف CSV الخاص بك
Add a column to your child CSV that references the parent using its unique identifier.
أضِف عمودًا إلى ملف CSV للتابع يشير إلى الأصل باستخدام مُعرّفه الفريد.
### Example: People Linking to Companies
### مثال: ربط الأشخاص بالشركات
**Your People CSV:**
**ملف CSV الخاص بالأشخاص لديك:**
```csv
firstName,lastName,email,jobTitle,companyDomain
@@ -106,66 +106,66 @@ Jane,Doe,jane@widgets.co,CTO,https://widgets.co
Bob,Johnson,bob@techstart.io,Developer,https://techstart.io
```
The `companyDomain` column references the Company's domain.
يشير عمود `companyDomain` إلى نطاق الشركة.
### Format Requirements
### متطلبات التنسيق
| معرّف | التنسيق | مثال |
| ----------------- | -------------- | -------------------------------------- |
| النطاق | URL format | `https://acme.com` |
| البريد الإلكتروني | Standard email | `john@acme.com` |
| المعرف | UUID | `c776ee49-f608-4a77-8cc8-6fe96ae1e43f` |
| معرّف | التنسيق | مثال |
| ----------------- | ------------------- | -------------------------------------- |
| النطاق | تنسيق عنوان URL | `https://acme.com` |
| البريد الإلكتروني | بريد إلكتروني قياسي | `john@acme.com` |
| المعرف | UUID | `c776ee49-f608-4a77-8cc8-6fe96ae1e43f` |
<Warning>
**Domain format matters!**
**تنسيق النطاق مهم!**
Use `https://domain.com` (not just `domain.com`). This matches how Twenty stores Company domains and prevents matching errors.
استخدم `https://domain.com` (وليس فقط `domain.com`). هذا يتوافق مع طريقة تخزين Twenty لنطاقات الشركات ويمنع أخطاء المطابقة.
</Warning>
### Important Rules
### قواعد مهمة
1. **Exact match required** — the value must exactly match the parent record
2. **Map only ONE unique identifier** — don't include both `companyId` AND `companyDomain`
3. **Case sensitive** — `Acme.com` ≠ `acme.com`
1. **تطابق تام مطلوب** — يجب أن تتطابق القيمة تمامًا مع سجل الأصل
2. **قم بتعيين مُعرّف فريد واحد فقط** — لا تُدرج كلًّا من `companyId` و`companyDomain`
3. **حسّاس لحالة الأحرف** — `Acme.com` ≠ `acme.com`
## Step 6: Upload and Map the Relation
## الخطوة 6: ارفع الملف وعيّن العلاقة
1. Navigate to the child object (e.g., People)
2. Click **⋮** → **Import records**
3. Upload your CSV file
4. In the field mapping step:
* Find your relation column (e.g., `companyDomain`)
* Map it to the **Company** relation field
5. Complete the remaining mapping
6. Review errors and confirm
1. انتقل إلى كائن التابع (مثلًا، الأشخاص)
2. انقر **⋮** → **Import records**
3. ارفع ملف CSV الخاص بك
4. في خطوة تعيين الحقول:
* اعثر على عمود العلاقة الخاص بك (مثلًا، `companyDomain`)
* طابقه مع حقل علاقة **Company**
5. أكمل التعيينات المتبقية
6. راجع الأخطاء وأكّد
Twenty will automatically link each child record to the matching parent.
سيقوم Twenty بربط كل سجل تابع تلقائيًا بالأصل المطابق.
## Step 7: Verify the Import
## الخطوة 7: التحقّق من الاستيراد
After importing:
بعد الاستيراد:
1. Open a few child records (e.g., People)
2. Verify the relation field shows the correct parent (e.g., Company)
3. Open a parent record and check the related records section
1. افتح عددًا قليلًا من سجلات التابع (مثلًا، الأشخاص)
2. تحقّق من أن حقل العلاقة يعرض الأصل الصحيح (مثلًا، الشركة)
3. افتح سجل الأصل وتفقّد قسم السجلات المرتبطة
## Common Mistakes to Avoid
## أخطاء شائعة يجب تجنّبها
| Mistake | Problem | Solution |
| -------------------------- | -------------------------------------------------- | ------------------------------------------------------- |
| **Wrong import order** | Importing People before Companies | Always import parents first, then children |
| **Wrong domain format** | Using `acme.com` instead of `https://acme.com` | Use full URL format with `https://` |
| **Multiple unique fields** | Mapping both `companyId` AND `companyDomain` | Map only ONE unique identifier |
| **Missing relation field** | The relation field doesn't exist in the data model | Create it in **Settings → Data Model** before importing |
| **Non-existent records** | The parent record doesn't exist in Twenty | Import parent records first, or check for typos |
| **Case mismatch** | `Acme.com` in file but `acme.com` in Twenty | Ensure exact case matching |
| الخطأ | المشكلة | الحل |
| ------------------------- | ---------------------------------------------- | ----------------------------------------------------------- |
| **ترتيب استيراد خاطئ** | استيراد الأشخاص قبل الشركات | استورد دائمًا الأصول أولًا، ثم التوابع |
| **تنسيق نطاق غير صحيح** | استخدام `acme.com` بدلًا من `https://acme.com` | استخدم تنسيق عنوان URL الكامل مع `https://` |
| **حقول فريدة متعددة** | تعيين كلٍّ من `companyId` و`companyDomain` | قم بتعيين مُعرّف فريد واحد فقط |
| **حقل علاقة مفقود** | حقل العلاقة غير موجود في نموذج البيانات | قم بإنشائه ضمن **الإعدادات → نموذج البيانات** قبل الاستيراد |
| **سجلات غير موجودة** | سجل الأصل غير موجود في Twenty | استورد سجلات الأصل أولًا، أو تحقّق من الأخطاء الإملائية |
| **عدم تطابق حالة الأحرف** | `Acme.com` في الملف ولكن `acme.com` في Twenty | تأكّد من تطابق حالة الأحرف تمامًا |
## Linking to Workspace Members
## الربط بأعضاء مساحة العمل
When linking to Workspace Members (your team):
عند الربط بأعضاء مساحة العمل (فريقك):
* Use their **email address**, not their name
* Example: `owner@yourcompany.com`, not "John Smith"
* استخدم **عنوان بريدهم الإلكتروني**، وليس اسمهم
* مثال: `owner@yourcompany.com`، وليس "John Smith"
```csv
taskName,assignedTo
@@ -173,56 +173,56 @@ Follow up with client,john@yourcompany.com
Review proposal,jane@yourcompany.com
```
## FAQ
## الأسئلة الشائعة
<AccordionGroup>
<Accordion title="What if my parent record doesn't have a domain or email?">
You have two options:
<Accordion title="ماذا لو لم يكن لدى سجل الأصل نطاق أو بريد إلكتروني؟">
لديك خياران:
1. Use the Twenty `id` (export parent records to get their IDs)
2. Create a custom unique field in your data model to store an external ID from your previous system
1. استخدم `id` الخاص بـ Twenty (صدّر سجلات الأصل للحصول على معرّفاتها)
2. أنشئ حقلًا فريدًا مخصصًا في نموذج البيانات لتخزين معرّف خارجي من نظامك السابق
</Accordion>
<Accordion title="Can I update relations on existing records?">
نعم! Include the child record's unique identifier (e.g., `email` for People) and the new relation value. The import will update the relation.
<Accordion title="هل يمكنني تحديث العلاقات على السجلات الموجودة؟">
نعم! ضمّن المُعرّف الفريد لسجل التابع (مثلًا، `email` للأشخاص) وقيمة العلاقة الجديدة. سيقوم الاستيراد بتحديث العلاقة.
</Accordion>
<Accordion title="Can I import Many-to-Many relationships?">
Many-to-Many relations are not yet supported for import. This is planned for H1 2026.
<Accordion title="هل يمكنني استيراد علاقات عديدة-إلى-عدة؟">
العلاقات عديدة-إلى-عدة غير مدعومة للاستيراد بعد. هذا مُخطّط للنصف الأول من عام 2026.
</Accordion>
<Accordion title="Can I link to multiple object types (like Notes to People AND Companies)?">
Relations pointing to multiple object types are not yet supported for import/export. This is on our roadmap.
<Accordion title="هل يمكنني الربط بأنواع كائنات متعددة (مثل ربط الملاحظات بالأشخاص والشركات معًا)؟">
العلاقات التي تشير إلى أنواع كائنات متعددة غير مدعومة للاستيراد/التصدير بعد. هذا على خارطة الطريق لدينا.
</Accordion>
<Accordion title="What happens if a parent record doesn't exist?">
The import will show an error for that row. يمكنك إما:
<Accordion title="ماذا يحدث إذا كان سجل الأصل غير موجود؟">
سيعرض الاستيراد خطأً لذلك الصف. يمكنك إما:
* Import the parent record first, then re-import
* Fix the reference value
* Remove the row from import
* استورد سجل الأصل أولًا، ثم أعد الاستيراد
* أصلِح قيمة المرجع
* أزل الصف من الاستيراد
</Accordion>
<Accordion title="Why is my relation not linking correctly?">
Common causes:
<Accordion title="لماذا لا يتم ربط العلاقة بشكل صحيح؟">
أسباب شائعة:
* Wrong format (use `https://domain.com` for domains)
* Case mismatch (check exact spelling)
* Parent doesn't exist (import parents first)
* Mapping multiple identifiers (use only one)
* تنسيق غير صحيح (استخدم `https://domain.com` للنطاقات)
* عدم تطابق حالة الأحرف (تحقّق من التهجئة الدقيقة)
* الأصل غير موجود (استورد الأصول أولًا)
* تعيين عدة مُعرّفات (استخدم واحدًا فقط)
</Accordion>
</AccordionGroup>
<Warning>
**Remember: Soft-deleted records count toward uniqueness.**
**تذكير: السجلات المحذوفة حذفًا ناعمًا تُحتسب ضمن التفرد.**
If you're getting "not found" errors but the record seems to exist, check Command Menu → See deleted records. The parent may have been soft-deleted.
إذا كنت تتلقى أخطاء "not found" ولكن يبدو أن السجل موجود، فتحقّق من قائمة الأوامر → عرض السجلات المحذوفة. قد يكون السجل الأصل قد حُذِف حذفًا منطقيًا.
</Warning>
## استكشاف الأخطاء وإصلاحها
Having issues? Check:
هل تواجه مشكلات؟ اطّلع على:
* [How to Fix Import Errors](/l/ar/user-guide/data-migration/how-tos/fix-import-errors)
* [Import Relations Capabilities](/l/ar/user-guide/data-migration/capabilities/import-relations)
* [Uniqueness Constraints](/l/ar/user-guide/data-migration/capabilities/uniqueness-constraints)
* [كيفية إصلاح أخطاء الاستيراد](/l/ar/user-guide/data-migration/how-tos/fix-import-errors)
* [قدرات استيراد العلاقات](/l/ar/user-guide/data-migration/capabilities/import-relations)
* [قيود التفرد](/l/ar/user-guide/data-migration/capabilities/uniqueness-constraints)
@@ -1,43 +1,43 @@
---
title: Migrating from Other CRMs
description: Step-by-step guide to migrate your data from any CRM to Twenty.
description: دليل خطوة بخطوة لترحيل بياناتك من أي نظام لإدارة علاقات العملاء إلى Twenty.
---
## نظرة عامة
This guide walks you through migrating your data from any CRM to Twenty. The process involves auditing your data, preparing your Twenty workspace, exporting from your current system, and importing into Twenty.
يرشدك هذا الدليل خلال عملية ترحيل بياناتك من أي نظام لإدارة علاقات العملاء إلى Twenty. تشمل العملية تدقيق بياناتك، وإعداد مساحة العمل في Twenty، والتصدير من نظامك الحالي، والاستيراد إلى Twenty.
<Note>Views, workflows, and permissions must be recreated manually after migration. Plan time for this configuration work.</Note>
<Note>يجب إعادة إنشاء العروض، وسير العمل، والأذونات يدويًا بعد الترحيل. خطط وقتًا لهذا العمل الخاص بالإعداد.</Note>
## Step 1: Audit Your Current Data
## الخطوة 1: تدقيق بياناتك الحالية
Migration is an opportunity for a fresh start. Don't bring over clutter.
يُعد الترحيل فرصة لبداية جديدة. لا تنقل البيانات غير الضرورية.
**What to keep:**
**ما يجب الاحتفاظ به:**
* Active contacts and companies
* Open opportunities and deals
* Important notes and activities
* Custom fields you actually use
* جهات الاتصال والشركات النشطة
* الفرص والصفقات المفتوحة
* الملاحظات والأنشطة المهمة
* الحقول المخصصة التي تستخدمها فعليًا
**What to leave behind:**
**ما يجب تركه:**
* Outdated contacts (no activity in 2+ years)
* Duplicate records
* Test data
* Unused custom fields
* جهات الاتصال القديمة (لا نشاط خلال سنتين أو أكثر)
* السجلات المكررة
* بيانات الاختبار
* الحقول المخصصة غير المستخدمة
## Step 2: Map Your Data Model
## الخطوة 2: مطابقة نموذج البيانات الخاص بك
Create a mapping document between your current CRM and Twenty:
أنشئ مستند مطابقة بين نظام إدارة علاقات العملاء الحالي لديك وTwenty:
| Your CRM | Twenty |
| ---------------------- | -------------------- |
| Account / Organization | **Company** |
| Contact / Person | **People** |
| Deal / Opportunity | **Opportunity** |
| Activity | **Task** or **Note** |
| Custom Object | **Custom Object** |
| نظام إدارة علاقات العملاء الخاص بك | Twenty |
| ---------------------------------- | -------------------- |
| حساب / مؤسسة | **الشركة** |
| جهة اتصال / شخص | **الأشخاص** |
| صفقة / فرصة | **الفرصة** |
| Activity | **Task** or **Note** |
| Custom Object | **Custom Object** |
**For each field, document:**
@@ -1,73 +1,73 @@
---
title: التحويل من نظام ذاتي الاستضافة إلى السحابة
description: Step-by-step guide to migrate your Twenty self-hosted instance to Twenty Cloud.
description: دليل خطوة بخطوة لترحيل مثيل Twenty ذاتي الاستضافة الخاص بك إلى Twenty Cloud.
---
## نظرة عامة
This guide walks you through migrating your data from a Twenty self-hosted instance to Twenty Cloud. The process involves setting up your cloud workspace, exporting your data, and re-importing it.
يرشدك هذا الدليل خلال ترحيل بياناتك من مثيل Twenty ذاتي الاستضافة إلى Twenty Cloud. تتضمن العملية إعداد مساحة العمل السحابية الخاصة بك، وتصدير بياناتك، ثم إعادة استيرادها.
<Note>Views, workflows, and roles must be recreated manually after migration. Plan time for this configuration work.</Note>
<Note>يجب إعادة إنشاء العروض، وسير العمل، والأدوار يدويًا بعد الترحيل. خطط وقتًا لهذا العمل الخاص بالإعداد.</Note>
## Step 1: Create Your Cloud Workspace
## الخطوة 1: إنشاء مساحة العمل السحابية الخاصة بك
1. Go to [app.twenty.com](https://app.twenty.com) and create a new workspace
2. Complete the initial setup wizard
3. Note your new workspace URL
1. انتقل إلى [app.twenty.com](https://app.twenty.com) وأنشئ مساحة عمل جديدة
2. أكمل معالج الإعداد الأولي
3. دوّن عنوان URL لمساحة العمل الجديدة لديك
## Step 2: Recreate Your Data Model
## الخطوة 2: إعادة إنشاء نموذج البيانات الخاص بك
Before importing data, recreate your custom objects and fields:
قبل استيراد البيانات، أعد إنشاء الكائنات والحقول المخصّصة لديك:
1. Go to **Settings → Data Model** in your cloud instance
2. Create custom objects that match your self-hosted setup
3. Add custom fields to standard and custom objects
4. Configure field settings (unique, required, etc.)
1. انتقل إلى **الإعدادات → نموذج البيانات** في مثيلك السحابي
2. أنشئ كائنات مخصّصة تتطابق مع إعدادك ذاتي الاستضافة
3. أضف حقولًا مخصّصة إلى الكائنات القياسية والمخصّصة
4. قم بضبط إعدادات الحقول (فريد، مطلوب، إلخ.)
<Note>Take screenshots of your self-hosted data model for reference, or keep both instances open side by side.</Note>
<Note>التقط لقطات شاشة لنموذج البيانات ذاتي الاستضافة لديك كمرجع، أو اترك المثيلين مفتوحين جنبًا إلى جنب.</Note>
## Step 3: Invite All Users
## الخطوة 3: دعوة جميع المستخدمين
<Warning>
**Critical: Invite users BEFORE importing data.**
**هام: قم بدعوة المستخدمين قبل استيراد البيانات.**
Users must accept their invitations before you import any records that reference them (like Account Owner fields). If users don't exist yet, those relations cannot be mapped.
يجب على المستخدمين قبول دعواتهم قبل أن تستورد أي سجلات تُشير إليهم (مثل حقول مالك الحساب). إذا لم يكن المستخدمون موجودين بعد، فلن يمكن تعيين تلك العلاقات.
</Warning>
1. Go to **Settings → Members** in your cloud instance
2. Invite all team members who had accounts on self-hosted
3. **Wait for everyone to accept** their invitation
4. Verify all users appear in your Members list
1. انتقل إلى **الإعدادات → الأعضاء** في مثيلك السحابي
2. ادعُ جميع أعضاء الفريق الذين كانت لديهم حسابات على المثيل ذاتي الاستضافة
3. **انتظر أن يقبل الجميع** دعواتهم
4. تحقق من ظهور جميع المستخدمين في قائمة الأعضاء لديك
## Step 4: Export Data from Self-Hosted
## الخطوة 4: تصدير البيانات من المثيل ذاتي الاستضافة
Export each object from your self-hosted instance:
صدِّر كل كائن من مثيلك ذاتي الاستضافة:
1. Navigate to each object (Companies, People, Opportunities, etc.)
2. Configure the view to show **all columns** you want to migrate
3. Click **⋮ → Export view**
4. Save each CSV file with a clear name (e.g., `companies-export.csv`)
1. انتقل إلى كل كائن (الشركات، الأشخاص، الفرص، إلخ.)
2. قم بإعداد العرض ليُظهر **جميع الأعمدة** التي تريد ترحيلها
3. انقر **⋮ → Export view**
4. احفظ كل ملف CSV باسم واضح (مثلًا، `companies-export.csv`)
**Export in this order** (for reference when importing):
**صدِّر بالترتيب التالي** (للرجوع إليه عند الاستيراد):
1. الشركات
2. الأشخاص
3. الفرص
4. Custom objects (following their dependencies)
5. Tasks, Notes
4. الكائنات المخصّصة (وفقًا لتبعياتها)
5. المهام، الملاحظات
## Step 5: Update Workspace Member References
## الخطوة 5: تحديث مراجع أعضاء مساحة العمل
The exported CSVs contain user IDs from your self-hosted instance. These IDs won't match your cloud instance, so you need to replace them with emails.
تحتوي ملفات CSV المُصدَّرة على معرّفات المستخدمين من مثيلك ذاتي الاستضافة. هذه المعرّفات لن تتطابق مع مثيلك السحابي، لذا تحتاج إلى استبدالها بعناوين البريد الإلكتروني.
**For each CSV file with user references (Owner, Assignee, etc.):**
**لكل ملف CSV يحتوي على مراجع للمستخدمين (المالك، المسند إليه، إلخ.):**
1. Open the CSV in a spreadsheet application
2. Add a new column next to each user ID column (e.g., `accountOwnerEmail` next to `accountOwnerId`)
3. Fill in the **email address** of each user
4. You can delete the old ID column or leave it (it will be skipped during import)
1. افتح ملف CSV في تطبيق جداول بيانات
2. أضِف عمودًا جديدًا بجوار كل عمود لمعرّف المستخدم (مثلًا، `accountOwnerEmail` بجوار `accountOwnerId`)
3. املأ **عنوان البريد الإلكتروني** لكل مستخدم
4. يمكنك حذف عمود المعرّف القديم أو تركه (سيتم تخطيه أثناء الاستيراد)
**Example:**
**مثال:**
قبل:
@@ -83,89 +83,89 @@ name,domain,accountOwnerEmail
Acme Corp,https://acme.com,john@yourcompany.com
```
<Note>Use the same email addresses that users used to accept their cloud workspace invitation.</Note>
<Note>استخدم عناوين البريد الإلكتروني نفسها التي استخدمها المستخدمون لقبول دعوتهم إلى مساحة العمل السحابية.</Note>
## Step 6: Plan Your Import Order
## الخطوة 6: التخطيط لترتيب الاستيراد
Import files in the correct order to maintain relationships:
استورد الملفات بالترتيب الصحيح للحفاظ على العلاقات:
1. **Companies** first (no dependencies)
2. **People** second (link to Companies)
3. **Opportunities** third (link to Companies and People)
4. **Custom objects** (following their dependencies)
5. **Tasks and Notes** last (link to other records)
1. **الشركات** أولًا (من دون تبعيات)
2. **الأشخاص** ثانيًا (مرتبطون بالشركات)
3. **الفرص** ثالثًا (مرتبطة بالشركات والأشخاص)
4. **الكائنات المخصّصة** (وفقًا لتبعياتها)
5. **المهام والملاحظات** أخيرًا (مرتبطة بسجلات أخرى)
See [How to Import Relations](/l/ar/user-guide/data-migration/how-tos/import-relations-between-objects-via-csv) for details on maintaining relationships.
اطّلع على [كيفية استيراد العلاقات](/l/ar/user-guide/data-migration/how-tos/import-relations-between-objects-via-csv) لمعرفة تفاصيل الحفاظ على العلاقات.
## Step 7: Import to Cloud
## الخطوة 7: الاستيراد إلى السحابة
For each CSV file, in order:
لكل ملف CSV، بالتسلسل:
1. Navigate to the object in your cloud instance
2. Click **⋮ → Import records**
3. Upload the CSV file
4. Map columns to fields:
* Map user email columns to the appropriate relation fields
* Map other columns as usual
5. Review and fix any errors
6. Confirm the import
7. Verify a few records before proceeding to the next file
1. انتقل إلى الكائن في مثيلك السحابي
2. انقر **⋮ → Import records**
3. ارفع ملف CSV
4. طابق الأعمدة مع الحقول:
* طابِق أعمدة بريد المستخدم الإلكتروني مع حقول العلاقات المناسبة
* طابق الأعمدة الأخرى كالمعتاد
5. راجِع وأصلِح أي أخطاء
6. أكِّد عملية الاستيراد
7. تحقّق من عدد قليل من السجلات قبل المتابعة إلى الملف التالي
## Step 8: Recreate Configuration
## الخطوة 8: إعادة إنشاء الإعدادات
After importing data, manually recreate:
بعد استيراد البيانات، أعد إنشاء ما يلي يدويًا:
### العروض
* Recreate saved views with filters, sorts, and column configurations
* Set up any kanban or calendar views
* أعد إنشاء العروض المحفوظة مع عوامل التصفية والترتيب وتكوينات الأعمدة
* قم بإعداد أي عروض كانبان أو تقويم
### سير العمل
* Recreate automations in **Settings → Workflows**
* Test each workflow before relying on it
* أعد إنشاء الأتمتة في **الإعدادات → سير العمل**
* اختبر كل سير عمل قبل الاعتماد عليه
### Roles and Permissions
### الأدوار والصلاحيات
* Configure roles in **Settings → Roles**
* Assign users to appropriate roles
* قم بتكوين الأدوار في **الإعدادات → الأدوار**
* عيّن المستخدمين إلى الأدوار المناسبة
### التكاملات
* Reconnect email and calendar sync for each user
* Reconfigure any API integrations with new API keys
* أعد توصيل مزامنة البريد الإلكتروني والتقويم لكل مستخدم
* أعد تكوين أي تكاملات API بمفاتيح API جديدة
## قائمة التحقق بعد التحويل
<Check>All data imported successfully</Check>
<Check>Relations between objects working correctly</Check>
<Check>User assignments (Owner, Assignee) mapped correctly</Check>
<Check>Views recreated</Check>
<Check>Workflows recreated and tested</Check>
<Check>Roles and permissions configured</Check>
<Check>Email/calendar sync reconnected</Check>
<Check>API integrations updated with new keys</Check>
<Check>تم استيراد جميع البيانات بنجاح</Check>
<Check>العلاقات بين الكائنات تعمل بشكل صحيح</Check>
<Check>تعيينات المستخدمين (المالك، المسند إليه) تمت مطابقتها بشكل صحيح</Check>
<Check>تمت إعادة إنشاء العروض</Check>
<Check>تمت إعادة إنشاء سير العمل واختبارها</Check>
<Check>تم تكوين الأدوار والصلاحيات</Check>
<Check>تمت إعادة توصيل مزامنة البريد الإلكتروني/التقويم</Check>
<Check>تم تحديث تكاملات API بمفاتيح جديدة</Check>
## FAQ
## الأسئلة الشائعة
<AccordionGroup>
<Accordion title="Can I migrate workflows automatically?">
Not currently. Workflows must be recreated manually in your cloud instance.
<Accordion title="هل يمكنني ترحيل سير العمل تلقائيًا؟">
ليس في الوقت الحالي. يجب إعادة إنشاء سير العمل يدويًا في مثيلك السحابي.
</Accordion>
<Accordion title="What about file attachments and images?">
File attachments are not included in CSV exports. You'll need to re-upload any attachments manually, migrate them via API or contact our team for assistance with large migrations.
<Accordion title="ماذا عن مرفقات الملفات والصور؟">
مرفقات الملفات غير متضمنة في صادرات CSV. ستحتاج إلى إعادة رفع أي مرفقات يدويًا، أو ترحيلها عبر API، أو التواصل مع فريقنا للحصول على المساعدة في عمليات الترحيل الكبيرة.
</Accordion>
<Accordion title="Can I keep both instances running during migration?">
Yes, we recommend keeping your self-hosted instance running until you've verified the cloud migration is complete. Just be careful not to create new data in both places.
<Accordion title="هل يمكنني إبقاء المثيلين يعملان أثناء الترحيل؟">
نعم، نوصي بإبقاء مثيلك ذاتي الاستضافة قيد التشغيل حتى تتحقق من اكتمال الترحيل إلى السحابة. فقط احرص على عدم إنشاء بيانات جديدة في كلا المكانين.
</Accordion>
<Accordion title="What if a user hasn't accepted their invitation yet?">
Records referencing that user will fail to import or the relation will be empty. Ensure all users accept invitations before importing data.
<Accordion title="ماذا لو لم يقبل مستخدم دعوته بعد؟">
السجلات التي تُشير إلى ذلك المستخدم ستفشل في الاستيراد أو ستكون العلاقة فارغة. تأكّد من أن جميع المستخدمين يقبلون الدعوات قبل استيراد البيانات.
</Accordion>
</AccordionGroup>
## هل تحتاج إلى مساعدة؟
For complex migrations or large datasets, contact us at [contact@twenty.com](mailto:contact@twenty.com) or explore our [Implementation Services](/l/ar/user-guide/getting-started/capabilities/implementation-services).
بالنسبة لعمليات الترحيل المعقّدة أو مجموعات البيانات الكبيرة، تواصل معنا عبر [contact@twenty.com](mailto:contact@twenty.com) أو اطّلع على [خدمات التنفيذ](/l/ar/user-guide/getting-started/capabilities/implementation-services).
@@ -42,10 +42,6 @@ The CRM has two fundamental types of records:
الحقل يشير إلى منطقة معينة يتم فيها تخزين بيانات محددة لكيان معين.
## التكامل
Integrations are built-in tools that allow you to link Twenty with other software or systems.
## مكرر
An Iterator is a workflow action that loops through an array of items, executing subsequent actions for each item in the list.
@@ -34,7 +34,7 @@ description: كل شركة تعمل بطريقة مختلفة. Start with these
* الحفاظ على تاريخ الاتصالات واضحًا لفريقك
**تستخدم مقدم خدمة آخر؟**
يمكنك إضافة بريد آخر عبر SMTP أو تقويم آخر عبر CalDAV. ستحتاج إلى تفعيل الميزة تحت الإعدادات → الإصدارات → المختبر، ثم العودة إلى علامة التبويب الإعدادات → الحسابات.
يمكنك إضافة بريد آخر عبر SMTP أو تقويم آخر عبر CalDAV. Go to **Settings → Accounts** to configure.
### استيراد البيانات عبر csv
@@ -20,7 +20,6 @@ On the left side, from the top to the bottom, you'll be able to:
* احصل على وصول مباشر إلى **العروض المفضلة** لديك. المفضلات فريدة لكل مستخدم.
* التبديل بين الكائنات المختلفة
* **Create automations** using workflows
* تواصل مع فريق الدعم وافتح دليل المستخدم الخاص بنا.
<img src="/images/user-guide/home/navigation-bar.png" style={{width:'100%'}} />
@@ -78,6 +77,8 @@ If you're new to Views, read our [Views & Pipelines guide](/l/ar/user-guide/view
* دعوة أعضاء الفريق وإدارة أدوار المستخدم
* تعديل ملف التعريف الخاص بك وتفضيلات مساحة العمل
* تكوين الفوترة ومراقبة استخدام اعتمادات سير العمل
* اكتشف أحدث الإصدارات والميزات القادمة (تحت قسم الإصدارات → علامة تبويب المختبر)
* Discover and enable upcoming features (under Updates → Early Access)
* **Access Support** to reach out via live chat
* **Open the Documentation** to browse the User Guide and developer docs
<Note>If you do not see all those sections under Settings, reach out to your workspace administrator - some of them have restricted access.</Note>
@@ -1,63 +1,63 @@
---
title: Discover Twenty
description: Welcome to Twenty User Guide, your resources for advanced configurations and best practices.
title: اكتشف Twenty
description: مرحباً بك في دليل مستخدم Twenty، مصادرك للإعدادات المتقدمة وأفضل الممارسات.
---
import { CardTitle } from "/snippets/card-title.mdx"
<CardGroup cols={٣}>
<Card href="/l/ar/user-guide/getting-started/capabilities/what-is-twenty" img="/images/user-guide/api/api.png">
<CardTitle>Discover Twenty</CardTitle>
Learn what Twenty is and how it can help your business.
<CardTitle>اكتشف Twenty</CardTitle>
تعرّف على ماهية Twenty وكيف يمكن أن تساعد عملك.
</Card>
<Card href="/l/ar/user-guide/data-model/overview" img="/images/user-guide/fields/custom_data_model.png">
<CardTitle>Data Model</CardTitle>
Customize your data model to fit your business processes.
<CardTitle>نموذج البيانات</CardTitle>
خصّص نموذج بياناتك ليتوافق مع عمليات عملك.
</Card>
<Card href="/l/ar/user-guide/data-migration/overview" img="/images/user-guide/import-export-data/cloud.png">
<CardTitle>Data Migration</CardTitle>
Import and export your data via CSV or API.
<CardTitle>ترحيل البيانات</CardTitle>
استورد بياناتك وصدّرها عبر CSV أو API.
</Card>
<Card href="/l/ar/user-guide/calendar-emails/overview" img="/images/user-guide/emails/emails_header.png">
<CardTitle>Calendar & Emails</CardTitle>
Centralize your team's meetings and emails.
<CardTitle>التقويم والبريد الإلكتروني</CardTitle>
جمّع اجتماعات فريقك ورسائله الإلكترونية في مكان واحد.
</Card>
<Card href="/l/ar/user-guide/workflows/overview" img="/images/user-guide/workflows/workflow.png">
<CardTitle>Workflows</CardTitle>
Automate processes and integrate with external tools.
<CardTitle>سير العمل</CardTitle>
أتمتة العمليات والتكامل مع الأدوات الخارجية.
</Card>
<Card href="/l/ar/user-guide/ai/overview" img="/images/user-guide/workflows/robot.png">
<CardTitle>AI</CardTitle>
Enhance your team with AI agents.
<CardTitle>الذكاء الاصطناعي</CardTitle>
عزّز فريقك بوكلاء الذكاء الاصطناعي.
</Card>
<Card href="/l/ar/user-guide/views-pipelines/overview" img="/images/user-guide/table-views/table_pink.png">
<CardTitle>Views & Pipelines</CardTitle>
Organize your data with actionable views and pipelines.
<CardTitle>طرق العرض والمسارات</CardTitle>
نظّم بياناتك من خلال طرق عرض عملية ومسارات.
</Card>
<Card href="/l/ar/user-guide/dashboards/overview" img="/images/user-guide/reporting/pie-chart.png">
<CardTitle>Dashboards</CardTitle>
Real-time insights to track performance.
<CardTitle>لوحات التحكم</CardTitle>
رؤى في الوقت الفعلي لتتبّع الأداء.
</Card>
<Card href="/l/ar/user-guide/permissions-access/overview" img="/images/user-guide/permissions/permissions.png">
<CardTitle>Permissions & Access</CardTitle>
Manage roles and access to Twenty.
<CardTitle>الأذونات والوصول</CardTitle>
أدِر الأدوار والوصول إلى Twenty.
</Card>
<Card href="/l/ar/user-guide/billing/overview" img="/images/user-guide/setup/pricing.png">
<CardTitle>Billing</CardTitle>
Understand how Twenty pricing and billing works.
<CardTitle>الفوترة</CardTitle>
تعرّف على كيفية عمل التسعير والفوترة في Twenty.
</Card>
<Card href="/l/ar/user-guide/settings/overview" img="/images/user-guide/setup/settings.png">
<CardTitle>Settings</CardTitle>
Configure your workspace preferences.
<CardTitle>الإعدادات</CardTitle>
قم بتكوين تفضيلات مساحة العمل الخاصة بك.
</Card>
</CardGroup>
@@ -1,126 +1,126 @@
---
title: Permissions FAQ
description: Frequently asked questions about roles and permissions.
title: الأسئلة الشائعة حول الصلاحيات
description: الأسئلة الشائعة حول الأدوار والصلاحيات.
---
## Roles
## الأدوار
<AccordionGroup>
<Accordion title="What roles come with Twenty by default?">
Twenty comes with an **Admin** and **Member** roles by default. You can create additional custom roles based on your team's needs (e.g., Sales Rep, Manager, Read-Only User).
<Accordion title="ما الأدوار التي تأتي مع Twenty افتراضيًا؟">
تتضمن Twenty بشكل افتراضي دوري **المشرف** و**العضو**. يمكنك إنشاء أدوار مخصصة إضافية بناءً على احتياجات فريقك (مثل: مندوب مبيعات، مدير، مستخدم للقراءة فقط).
</Accordion>
<Accordion title="Can I delete the Admin role?">
No, the Admin role cannot be deleted. There must always be at least one member assigned to the Admin role.
<Accordion title="هل يمكنني حذف دور المشرف؟">
لا، لا يمكن حذف دور المشرف. يجب دائمًا أن يكون هناك عضو واحد على الأقل معيّنًا إلى دور المشرف.
</Accordion>
<Accordion title="What happens when I delete a role?">
Any workspace member assigned to that role will be automatically reassigned to the default role.
<Accordion title="ماذا يحدث عند حذف دور؟">
سيُعاد تعيين أي عضو في مساحة العمل مُعيَّن إلى ذلك الدور تلقائيًا إلى الدور الافتراضي.
</Accordion>
<Accordion title="How do I set a default role for new members?">
Go to **Settings → Roles**, find the **Default Role** option, and select which role new members should automatically receive when they join.
<Accordion title="كيف أعيّن دورًا افتراضيًا للأعضاء الجدد؟">
انتقل إلى **Settings → Roles**، وابحث عن خيار **Default Role**، ثم اختر الدور الذي يجب أن يحصل عليه الأعضاء الجدد تلقائيًا عند انضمامهم.
</Accordion>
<Accordion title="Can I assign multiple roles to one user?">
No, each user can only have one role at a time. Create a custom role if you need a combination of permissions.
<Accordion title="هل يمكنني تعيين عدة أدوار لمستخدم واحد؟">
لا، يمكن لكل مستخدم امتلاك دور واحد فقط في كل مرة. أنشئ دورًا مخصصًا إذا كنت تحتاج إلى مجموعة من الصلاحيات.
</Accordion>
</AccordionGroup>
## الصلاحيات
<AccordionGroup>
<Accordion title="What's the difference between object and field permissions?">
* **Object permissions**: Control access to entire records (e.g., can see/edit/delete People records)
* **Field permissions**: Control access to specific fields within an object (e.g., can see but not edit the Salary field)
<Accordion title="ما الفرق بين صلاحيات الكائن وصلاحيات الحقل؟">
* **صلاحيات الكائن**: تتحكم في الوصول إلى السجلات بالكامل (مثلاً: يمكن رؤية/تعديل/حذف سجلات الأشخاص)
* **صلاحيات الحقل**: تتحكم في الوصول إلى حقول محددة داخل الكائن (مثلاً: يمكن رؤية حقل الراتب لكن لا يمكن تعديله)
Field permissions allow more granular control over sensitive data.
تتيح صلاحيات الحقول تحكّمًا أكثر تفصيلاً بالبيانات الحساسة.
</Accordion>
<Accordion title="How do permission overrides work?">
Permissions cascade from global to specific:
<Accordion title="كيف تعمل تجاوزات الصلاحيات؟">
تتدرّج الصلاحيات من العام إلى المحدّد:
1. **All Objects** sets the baseline for all objects
2. **Object-Level Permissions** can override the global setting for specific objects
3. **Field-Level Permissions** can override the object setting for specific fields
1. **All Objects** يحدّد الأساس لجميع الكائنات
2. **Object-Level Permissions** يمكنها تجاوز الإعداد العام لكائنات محددة
3. **Field-Level Permissions** يمكنها تجاوز إعداد الكائن لحقول محددة
More specific settings always take precedence.
الإعدادات الأكثر تحديدًا لها الأسبقية دائمًا.
</Accordion>
<Accordion title="What do the different permission levels mean?">
For objects:
<Accordion title="ماذا تعني مستويات الصلاحيات المختلفة؟">
بالنسبة إلى الكائنات:
* **See Records**: View records in lists and detail pages
* **Edit Records**: Modify existing records
* **Delete Records**: Soft-delete records (can be restored)
* **Destroy Records**: Permanently delete records
* **See Records**: عرض السجلات في القوائم وصفحات التفاصيل
* **Edit Records**: تعديل السجلات الحالية
* **Delete Records**: حذف السجلات حذفًا غير نهائي (يمكن استعادتها)
* **Destroy Records**: حذف السجلات نهائيًا
For fields:
بالنسبة إلى الحقول:
* **See Field**: View the field value
* **Edit Field**: Modify the field value
* **No Access**: Field is completely hidden
* **See Field**: عرض قيمة الحقل
* **Edit Field**: تعديل قيمة الحقل
* **No Access**: الحقل مخفي بالكامل
</Accordion>
<Accordion title="Can I restrict access to specific records (row-level permissions)?">
Row-level permissions will be available on the **Organization** plan by Q1 2026. This allows you to restrict access to specific records based on criteria (e.g., only see your own opportunities).
<Accordion title="هل يمكنني تقييد الوصول إلى سجلات محددة (صلاحيات على مستوى الصف)؟">
ستكون الصلاحيات على مستوى الصف متاحة ضمن خطة **Organization** بحلول الربع الأول من عام 2026. يتيح لك ذلك تقييد الوصول إلى سجلات محددة بناءً على معايير معينة (مثل: رؤية فرصك الخاصة فقط).
</Accordion>
<Accordion title="How do I make a field read-only for certain users?">
<Accordion title="كيف أجعل حقلًا للقراءة فقط لمستخدمين معيّنين؟">
1. اذهب إلى **الإعدادات → الأدوار**
2. Select the role
3. Navigate to the object containing the field
4. Set the field permission to **See Field** (without Edit Field)
2. اختر الدور
3. انتقل إلى الكائن الذي يحتوي على الحقل
4. عيّن صلاحية الحقل إلى **See Field** (من دون Edit Field)
</Accordion>
</AccordionGroup>
## Settings & Actions
## الإعدادات والإجراءات
<AccordionGroup>
<Accordion title="What settings permissions are available?">
You can control access to:
<Accordion title="ما صلاحيات الإعدادات المتاحة؟">
يمكنك التحكّم في الوصول إلى:
* API key generation
* Workspace preferences
* Role assignment
* Data model configuration
* Security settings
* Workflow management
* إنشاء مفتاح API
* تفضيلات مساحة العمل
* تعيين الأدوار
* تكوين نموذج البيانات
* إعدادات الأمان
* إدارة سير العمل
Use **Settings All Access** to grant full access, or enable specific permissions.
استخدم **Settings All Access** لمنح وصول كامل، أو فعّل صلاحيات محددة.
</Accordion>
<Accordion title="What action permissions are available?">
You can control:
<Accordion title="ما صلاحيات الإجراءات المتاحة؟">
يمكنك التحكّم في:
* **Send Email**: Ability to send emails from Twenty
* **Import CSV**: Ability to import data via CSV
* **Export CSV**: Ability to export data to CSV
* **Send Email**: إمكانية إرسال رسائل بريد إلكتروني من Twenty
* **Import CSV**: إمكانية استيراد البيانات عبر CSV
* **Export CSV**: إمكانية تصدير البيانات إلى CSV
Use **Application All Access** to grant all actions, or enable specific ones.
استخدم **Application All Access** لمنح جميع الإجراءات، أو فعّل إجراءات محددة.
</Accordion>
</AccordionGroup>
## التسجيل الموحد
<AccordionGroup>
<Accordion title="Is SSO available on all plans?">
No, SSO is a Premium feature available on the **Organization** plan only.
<Accordion title="هل ميزة SSO متاحة في جميع الخطط؟">
لا، SSO ميزة Premium متاحة ضمن خطة **Organization** فقط.
</Accordion>
<Accordion title="Which identity providers are supported?">
Twenty supports:
<Accordion title="ما موفّرو الهوية المدعومون؟">
تدعم Twenty:
* **SAML 2.0** (works with most enterprise identity providers)
* **SAML 2.0** (يعمل مع معظم موفّري الهوية للمؤسسات)
* **Google Workspace**
* **Microsoft Entra ID** (formerly Azure AD)
* **Microsoft Entra ID** (سابقًا Azure AD)
</Accordion>
<Accordion title="What is Just-in-Time (JIT) provisioning?">
With JIT provisioning, user accounts are automatically created in Twenty when someone logs in via SSO for the first time. They're assigned the default role automatically.
<Accordion title="ما هو التزويد Just-in-Time (JIT)؟">
مع التزويد JIT، يتم إنشاء حسابات المستخدمين تلقائيًا في Twenty عند تسجيل الدخول عبر SSO للمرة الأولى. ويُعيَّن لهم الدور الافتراضي تلقائيًا.
</Accordion>
<Accordion title="Can I require SSO for all users?">
Yes, once SSO is configured, you can disable password login for SSO users to enforce authentication through your identity provider.
<Accordion title="هل يمكنني فرض SSO على جميع المستخدمين؟">
نعم، بمجرد تكوين SSO يمكنك تعطيل تسجيل الدخول بكلمة المرور لمستخدمي SSO لفرض المصادقة عبر موفّر الهوية لديك.
</Accordion>
</AccordionGroup>
@@ -0,0 +1,36 @@
---
title: Updates Settings
description: Enable Early Access features in Twenty.
---
## About Updates Settings
The Updates section allows you to enable Early Access features before they're generally available.
## Early Access Features
Early Access features are capabilities that are still being tested before general availability.
**Currently in Early Access:**
* **Dashboards** — Visual reporting and analytics
### How to Enable Early Access Features
1. Go to **Settings → Updates**
2. Navigate to the **Early Access** section
3. Find the feature you want to enable
4. Toggle it on
5. The feature will be available immediately
<Note>
Early Access features may change based on user feedback. Your input helps us improve Twenty!
</Note>
## Feature Feedback
Your feedback helps improve Twenty:
* Report issues with Early Access features
* Share how you're using new features
* Suggest improvements via the community Discord
@@ -1,136 +1,136 @@
---
title: أسئلة شائعة حول الإعدادات
description: Frequently asked questions about Twenty settings.
description: الأسئلة الشائعة حول إعدادات Twenty.
image: /images/user-guide/setup/settings.png
---
## إعدادات مساحة العمل
<AccordionGroup>
<Accordion title="How do I change my workspace name?">
1. Go to **Settings → General**
2. Find the Workspace Name field
3. Enter your new name
4. Changes save automatically
<Accordion title="كيف أغيّر اسم مساحة العمل الخاصة بي؟">
1. اذهب إلى **الإعدادات → عام**
2. ابحث عن حقل اسم مساحة العمل
3. أدخل الاسم الجديد
4. يتم حفظ التغييرات تلقائيًا
</Accordion>
<Accordion title="How do I update my workspace logo?">
1. Go to **Settings → General**
2. Click on the current logo or upload area
3. Select an image file (PNG, JPEG, or GIF under 10MB)
4. The logo updates immediately
<Accordion title="كيف أحدّث شعار مساحة العمل الخاصة بي؟">
1. اذهب إلى **الإعدادات → عام**
2. انقر على الشعار الحالي أو منطقة التحميل
3. اختر ملف صورة (PNG أو JPEG أو GIF أصغر من 10MB)
4. يتم تحديث الشعار فورًا
</Accordion>
<Accordion title="Can I have multiple workspaces?">
Yes, you can create and be a member of multiple workspaces. Each workspace has its own data, settings, and subscription.
<Accordion title="هل يمكنني امتلاك عدة مساحات عمل؟">
نعم، يمكنك إنشاء عدة مساحات عمل وأن تكون عضوًا فيها. لكل مساحة عمل بياناتها وإعداداتها واشتراكها الخاص.
</Accordion>
<Accordion title="How do I delete my workspace?">
1. Go to **Settings → General**
2. Scroll to Danger Zone
3. Click **Delete workspace**
4. Confirm the deletion
<Accordion title="كيف أحذف مساحة العمل الخاصة بي؟">
1. اذهب إلى **الإعدادات → عام**
2. قم بالتمرير إلى منطقة الخطر
3. انقر **حذف مساحة العمل**
4. أكد الحذف
Note: This permanently deletes all data and cannot be undone.
ملاحظة: يؤدي هذا إلى حذف جميع البيانات بشكل دائم ولا يمكن التراجع عنه.
</Accordion>
<Accordion title="I accidentally created multiple workspaces. ماذا يجب أن أفعل؟">
Delete the workspaces you no longer need under **Settings → General → Delete workspace**.
<Accordion title="لقد أنشأت مساحات عمل متعددة عن طريق الخطأ. ماذا يجب أن أفعل؟">
احذف مساحات العمل التي لم تعد تحتاجها ضمن **الإعدادات → عام → حذف مساحة العمل**.
<Warning>
Do not delete your **account** (accessible under Settings → Profile): your account is shared among all your workspaces. Deleting your account removes access to ALL workspaces.
لا تحذف **حسابك** (يمكن الوصول إليه ضمن الإعدادات → الملف الشخصي): حسابك مشترك بين جميع مساحات العمل لديك. حذف حسابك يزيل الوصول إلى جميع مساحات العمل.
</Warning>
</Accordion>
<Accordion title="How do I disable my workspace without deleting it?">
If you want to temporarily disable your workspace (not permanently delete it), go to **Settings → Billing** and click **Cancel Plan**. Your data will be preserved for a grace period.
<Accordion title="كيف أعطّل مساحة العمل الخاصة بي دون حذفها؟">
إذا كنت تريد تعطيل مساحة العمل مؤقتًا (وليس حذفها نهائيًا)، فاذهب إلى **الإعدادات → الفوترة** وانقر **إلغاء الخطة**. سيتم الاحتفاظ ببياناتك لفترة سماح.
</Accordion>
</AccordionGroup>
## إعدادات الملف الشخصي
<AccordionGroup>
<Accordion title="How do I change my password?">
1. Go to **Settings → Profile**
2. Find the Password section
3. Enter your current password
4. Enter your new password
5. Save changes
<Accordion title="كيف أغيّر كلمة المرور الخاصة بي؟">
1. اذهب إلى **الإعدادات → الملف الشخصي**
2. ابحث عن قسم كلمة المرور
3. أدخل كلمة المرور الحالية
4. أدخل كلمة المرور الجديدة
5. احفظ التغييرات
</Accordion>
<Accordion title="How do I enable two-factor authentication?">
1. Go to **Settings → Profile**
2. Find the 2FA section
<Accordion title="كيف أفعّل المصادقة الثنائية؟">
1. اذهب إلى **الإعدادات → الملف الشخصي**
2. ابحث عن قسم المصادقة الثنائية (2FA)
3. انقر على **تمكين المصادقة الثنائية**
4. قم بمسح رمز الاستجابة السريعة باستخدام تطبيق المصادقة الخاص بك
5. Enter the verification code
5. أدخل رمز التحقق
</Accordion>
<Accordion title="Can I change my email address?">
To change your email address, please reach out to [contact@twenty.com](mailto:contact@twenty.com).
<Accordion title="هل يمكنني تغيير عنوان بريدي الإلكتروني؟">
لتغيير عنوان بريدك الإلكتروني، يُرجى التواصل عبر [contact@twenty.com](mailto:contact@twenty.com).
</Accordion>
<Accordion title="How do I delete my account?">
1. Go to **Settings → Profile**
2. Scroll to Danger Zone
3. Click **Delete Account**
4. Confirm by typing your email
<Accordion title="كيف أحذف حسابي؟">
1. اذهب إلى **الإعدادات → الملف الشخصي**
2. قم بالتمرير إلى منطقة الخطر
3. انقر **حذف الحساب**
4. أكد بكتابة بريدك الإلكتروني
Note: This removes your access to all workspaces and deletes all emails synced from your connected accounts.
ملاحظة: يؤدي هذا إلى إزالة وصولك إلى جميع مساحات العمل وحذف جميع الرسائل الإلكترونية المتزامنة من حساباتك المتصلة.
</Accordion>
</AccordionGroup>
## إعدادات التجربة
<AccordionGroup>
<Accordion title="How do I switch between light and dark mode?">
1. Go to **Settings → Experience**
2. Find the Theme section
3. Select Light, Dark, or System
<Accordion title="كيف أبدّل بين الوضع الفاتح والوضع الداكن؟">
1. اذهب إلى **الإعدادات → التجربة**
2. ابحث عن قسم السمة
3. اختر الفاتح، الداكن، أو النظام
</Accordion>
<Accordion title="How do I change the date format?">
1. Go to **Settings → Experience**
2. Find Date Format
3. Select your preferred format
4. Changes apply immediately
<Accordion title="كيف أغيّر تنسيق التاريخ؟">
1. اذهب إلى **الإعدادات → التجربة**
2. ابحث عن تنسيق التاريخ
3. اختر التنسيق المفضّل لديك
4. تُطبَّق التغييرات فورًا
</Accordion>
<Accordion title="How do I change my time zone?">
1. Go to **Settings → Experience**
2. Find Time Zone
3. Select your local time zone
4. All timestamps will adjust
<Accordion title="كيف أغيّر المنطقة الزمنية الخاصة بي؟">
1. اذهب إلى **الإعدادات → التجربة**
2. ابحث عن المنطقة الزمنية
3. اختر منطقتك الزمنية المحلية
4. سيتم ضبط جميع الطوابع الزمنية
</Accordion>
<Accordion title="Can I change the language?">
1. Go to **Settings → Experience**
2. Find Language
3. Select from available languages
4. The interface updates to your selection
<Accordion title="هل يمكنني تغيير اللغة؟">
1. اذهب إلى **الإعدادات → التجربة**
2. ابحث عن اللغة
3. اختر من اللغات المتاحة
4. سيتم تحديث الواجهة وفق اختيارك.
</Accordion>
</AccordionGroup>
## Account Settings
## إعدادات الحساب
<AccordionGroup>
<Accordion title="How do I connect my email account?">
<Accordion title="كيف أربط حساب البريد الإلكتروني الخاص بي؟">
1. اذهب إلى **الإعدادات → الحسابات**
2. انقر على **إضافة حساب**
3. Choose Google or Microsoft
4. Authorize access
5. Configure sync settings
3. اختر Google أو Microsoft
4. اسمح بالوصول
5. اضبط إعدادات المزامنة
</Accordion>
<Accordion title="Can I connect multiple email accounts?">
Yes, you can connect multiple email accounts. Go to **Settings → Accounts** and add additional accounts as needed.
<Accordion title="هل يمكنني ربط عدة حسابات بريد إلكتروني؟">
نعم، يمكنك ربط عدة حسابات بريد إلكتروني. اذهب إلى **الإعدادات → الحسابات** وأضف حسابات إضافية حسب الحاجة.
</Accordion>
<Accordion title="How do I disconnect an email account?">
<Accordion title="كيف أفصل حساب بريد إلكتروني؟">
1. اذهب إلى **الإعدادات → الحسابات**
2. Find the account to remove
3. Click **Disconnect**
4. Confirm the action
2. ابحث عن الحساب المراد إزالته
3. انقر **قطع الاتصال**
4. أكد الإجراء
</Accordion>
</AccordionGroup>
@@ -138,34 +138,34 @@ image: /images/user-guide/setup/settings.png
<AccordionGroup>
<Accordion title="هل يمكنني تخصيص دومين مساحة العمل الخاصة بي؟">
نعم! Go to **Settings → Domains** and click **Customize Domain**. You have two options:
نعم! اذهب إلى **الإعدادات → النطاقات** ثم انقر **تخصيص النطاق**. لديك خياران:
* **Subdomain**: Use a Twenty subdomain like `yourcompany.twenty.com`
* **Custom domain**: Use your own domain like `crm.yourcompany.com` (requires DNS configuration)
* **النطاق الفرعي**: استخدم نطاقًا فرعيًا من Twenty مثل `yourcompany.twenty.com`
* **نطاق مخصص**: استخدم نطاقك الخاص مثل `crm.yourcompany.com` (يتطلب تهيئة DNS)
A subdomain is quick to set up, while a custom domain provides a fully branded experience for your team.
إعداد النطاق الفرعي سريع، بينما يوفّر النطاق المخصص تجربة بعلامتك التجارية بالكامل لفريقك.
</Accordion>
<Accordion title="How do approved access domains work?">
You can configure approved access domains so team members with company email addresses can automatically join your workspace. Go to **Settings → Domains** and add your company domain (e.g., `yourcompany.com`).
<Accordion title="كيف تعمل نطاقات الوصول المعتمدة؟">
يمكنك تكوين نطاقات الوصول المعتمدة بحيث يتمكن أعضاء الفريق ذوو عناوين البريد الإلكتروني الخاصة بالشركة من الانضمام تلقائيًا إلى مساحة العمل الخاصة بك. اذهب إلى **الإعدادات → النطاقات** وأضف نطاق شركتك (مثلًا، `yourcompany.com`).
</Accordion>
</AccordionGroup>
## ميزات المختبر
## Early Access Features
<AccordionGroup>
<Accordion title="What are Lab features?">
Lab features are experimental capabilities being tested before general release. They may change or be removed without notice.
<Accordion title="What are Early Access features?">
Early Access features are capabilities being tested before general release. Currently, only **Dashboards** are in Early Access. They may change based on user feedback.
</Accordion>
<Accordion title="Are Lab features safe to use?">
Lab features are functional but may have bugs or unexpected behavior. Use them cautiously in production environments.
<Accordion title="Are Early Access features safe to use?">
Early Access features are functional but may change based on user feedback. They are safe to use but may evolve before general availability.
</Accordion>
<Accordion title="How do I enable Lab features?">
1. Go to **Settings → Releases → Lab**
2. Find the feature you want
3. Toggle it on
4. The feature becomes available immediately
<Accordion title="How do I enable Early Access features?">
1. Go to **Settings → Updates → Early Access**
2. ابحث عن الميزة التي تريدها
3. قم بتفعيلها
4. تصبح الميزة متاحة على الفور
</Accordion>
</AccordionGroup>
@@ -1,6 +1,6 @@
---
title: \ا\ل\إ\ع\د\ا\د\ا
description: Set up your Twenty workspace with essential configurations.
description: قم بإعداد مساحة عملك في Twenty باستخدام التكوينات الأساسية.
image: /images/user-guide/setup/settings.png
---
@@ -8,60 +8,60 @@ image: /images/user-guide/setup/settings.png
<img src="/images/user-guide/setup/settings.png" alt="\ا\ل\إ\ع\د\ا\د\ا\ت" />
</Frame>
## Initial Setup
## الإعداد الأولي
When you first create your workspace, there are several key settings to configure.
عند إنشاء مساحة العمل لأول مرة، توجد عدة إعدادات أساسية لتكوينها.
### Workspace Name and Logo
### اسم مساحة العمل والشعار
1. Go to **Settings → General**
2. Update your workspace name
3. Upload your company logo
4. Save your changes
1. اذهب إلى **الإعدادات → عام**
2. حدّث اسم مساحة العمل
3. حمّل شعار شركتك
4. احفظ التغييرات
### Time Zone and Date Format
### المنطقة الزمنية وتنسيق التاريخ
1. Go to **Settings → Experience**
2. Select your time zone
3. Choose your preferred date format
4. Save your changes
1. اذهب إلى **الإعدادات → التجربة**
2. اختر منطقتك الزمنية
3. اختر تنسيق التاريخ المفضّل لديك
4. احفظ التغييرات
## Essential Configurations
## التكوينات الأساسية
### Connect Email and Calendar
### اربط البريد الإلكتروني والتقويم
Set up email and calendar sync:
إعداد مزامنة البريد الإلكتروني والتقويم:
1. اذهب إلى **الإعدادات → الحسابات**
2. انقر على **إضافة حساب**
3. Connect your Google or Microsoft account
4. Configure sync settings
3. اربط حساب Google أو Microsoft الخاص بك
4. اضبط إعدادات المزامنة
→ [Complete email & calendar setup guide](/l/ar/user-guide/calendar-emails/overview)
→ [دليل شامل لإعداد البريد الإلكتروني والتقويم](/l/ar/user-guide/calendar-emails/overview)
### Invite Your Team
### ادعُ فريقك
Add team members to your workspace:
أضف أعضاء الفريق إلى مساحة العمل:
1. انتقل إلى **الإعدادات → الأعضاء**
2. Click **+ Invite**
3. Enter email addresses
4. Assign appropriate roles
2. انقر **+ دعوة**
3. أدخل عناوين البريد الإلكتروني
4. عيّن الأدوار المناسبة
<Note>
Before inviting your team, check the default role under **Settings → Roles**. New members are automatically assigned this role when they join.
قبل دعوة فريقك، تحقّق من الدور الافتراضي ضمن **الإعدادات → الأدوار**. يتم تعيين هذا الدور تلقائيًا للأعضاء الجدد عند انضمامهم.
</Note>
## Workspace Settings Checklist
## قائمة التحقق لإعدادات مساحة العمل
* Workspace name and logo configured
* Time zone and date format set
* Email and calendar connected
* Team members invited
* Roles and permissions configured
* تم تكوين اسم مساحة العمل والشعار
* تم ضبط المنطقة الزمنية وتنسيق التاريخ
* تم ربط البريد الإلكتروني والتقويم
* تمت دعوة أعضاء الفريق
* تم إعداد الأدوار والأذونات
## الخطوات التالية
* [Workspace settings](/l/ar/user-guide/settings/capabilities/workspace-settings)
* [Profile settings](/l/ar/user-guide/settings/capabilities/profile-settings)
* [Experience settings](/l/ar/user-guide/settings/capabilities/experience-settings)
* [إعدادات مساحة العمل](/l/ar/user-guide/settings/capabilities/workspace-settings)
* [إعدادات الملف الشخصي](/l/ar/user-guide/settings/capabilities/profile-settings)
* [إعدادات التجربة](/l/ar/user-guide/settings/capabilities/experience-settings)
@@ -1,120 +1,120 @@
---
title: Set Up a Sales Pipeline
description: Configure your sales pipeline to track opportunities through stages.
title: إعداد مسار المبيعات
description: قم بتهيئة مسار المبيعات لديك لتتبّع الفرص عبر المراحل.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
A sales pipeline in Twenty is a Kanban view of your Opportunities object, where each column represents a stage in your sales process.
يمثّل مسار المبيعات في Twenty عرض كانبان لكائن الفرص لديك، حيث يمثّل كل عمود مرحلة في عملية المبيعات الخاصة بك.
## Step 1: Configure Your Stages
## الخطوة 1: تهيئة المراحل الخاصة بك
Stages are defined in the Opportunities object's **Stage** field.
تُحدَّد المراحل في حقل **Stage** الخاص بكائن الفرص.
1. Go to **Settings → Data Model**
2. Select **Opportunities**
3. Find and click the **Stage** field
4. Add, remove, or rename stages to match your process
1. اذهب إلى **الإعدادات → نموذج البيانات**
2. حدّد **الفرص**
3. ابحث عن حقل **Stage** وانقر عليه
4. أضِف المراحل أو أزلها أو أعد تسميتها بما يتوافق مع عمليتك
<VimeoEmbed videoId="927890428" title="Video demonstration" />
<VimeoEmbed videoId="927890428" title="عرض توضيحي بالفيديو" />
### Recommended Stages
### المراحل الموصى بها
| المرحلة | Purpose |
| --------------- | ----------------------------------- |
| **New** | Fresh opportunities just identified |
| **Qualified** | Confirmed as a good fit |
| **Meeting** | Engaged in discussions |
| **Proposal** | Proposal sent |
| **Negotiation** | Working on terms |
| **Closed Won** | Deal successful |
| **Closed Lost** | Deal unsuccessful |
| المرحلة | الغرض |
| ----------------- | ----------------------------- |
| **جديد** | فرص جديدة تم تحديدها للتو |
| **مؤهل** | تم التأكّد من ملاءمتها الجيدة |
| **اجتماع** | تجري مناقشات |
| **عرض** | تم إرسال العرض |
| **تفاوض** | جارٍ العمل على الشروط |
| **مغلقة - رابحة** | صفقة ناجحة |
| **مغلقة - خاسرة** | صفقة غير ناجحة |
<Note>
**5-7 stages is optimal.** Too many stages makes the pipeline hard to scan; too few loses visibility into deal progress.
**أفضل عدد هو 5–7 مراحل.** كثرة المراحل تجعل مسار المبيعات صعب الاستعراض؛ وقلّتها تُفقد الرؤية لتقدّم الصفقات.
</Note>
## Step 2: Create a Pipeline View
## الخطوة 2: إنشاء عرض لمسار المبيعات
1. Go to **Opportunities**
2. Click the view dropdown → **+ Add view**
3. Name it "Sales Pipeline"
4. Click **Create**
5. Open **Options** and select **Kanban** as the layout
1. اذهب إلى **الفرص**
2. انقر على القائمة المنسدلة لطريقة العرض → **+ إضافة طريقة عرض**
3. سمِّه "مسار المبيعات"
4. انقر على **إنشاء**
5. افتح **الخيارات** واختر **Kanban** كتخطيط
The view automatically uses the Stage field for columns.
يستخدم العرض تلقائيًا حقل Stage للأعمدة.
## Step 3: Configure Your View
## الخطوة 3: تهيئة العرض الخاص بك
### Show Key Fields
### إظهار الحقول الرئيسية
1. Click **Options → Fields**
2. Look for fields in the "Hidden Fields" section
3. Click the **eye icon** to display: Company, Amount, Close Date, Owner
1. انقر على **الخيارات → الحقول**
2. ابحث عن الحقول في قسم "الحقول المخفية"
3. انقر على **أيقونة العين** لعرض: Company، Amount، Close Date، Owner
### Enable Aggregations
### تمكين عمليات التجميع
Show totals at the top of each column:
إظهار الإجماليات أعلى كل عمود:
1. Click the number displayed next to a Stage name at the top of a column
2. Select the aggregation type (Count, Sum, Average, etc.)
3. Choose the field to aggregate (e.g., Amount)
1. انقر على الرقم المعروض بجانب اسم Stage أعلى العمود
2. حدّد نوع التجميع (Count، Sum، Average، إلخ)
3. اختر الحقل المراد تجميعه (مثال: Amount)
**Example:** Show total deal value per stage by aggregating Amount with Sum.
**مثال:** اعرض إجمالي قيمة الصفقة لكل مرحلة من خلال تجميع Amount باستخدام Sum.
### Use Compact View (Optional)
### استخدم العرض المضغوط (اختياري)
For a high-level overview with minimal card content:
للحصول على نظرة عامة عالية المستوى مع أدنى قدر من محتوى البطاقات:
1. Click **Options**
2. Turn on the toggle for **Compact view**
1. انقر على **الخيارات**
2. فعِّل مفتاح التبديل لخيار **العرض المضغوط**
## Step 4: Create Personal and Team Views
## الخطوة 4: إنشاء عروض شخصية وعروض للفريق
### "My Pipeline"
### "مسار المبيعات الخاص بي"
* **Filter**: Owner = Me
* **Visibility**: Unlisted (personal view)
* **عامل التصفية**: Owner = Me
* **الظهور**: غير مُدرَج (عرض شخصي)
### "Team Pipeline"
### "مسار المبيعات للفريق"
* **Filter**: None (show all)
* **Visibility**: Workspace (shared view)
* **عامل التصفية**: None (عرض الكل)
* **الظهور**: Workspace (عرض مشترك)
### "Closing This Month"
### "الإغلاق هذا الشهر"
* **Type**: Table
* **Filter**: Close Date = This month, Stage ≠ Closed Won, Stage ≠ Closed Lost
* **Sort**: Close Date ascending
* **النوع**: Table
* **عامل التصفية**: Close Date = This month، Stage ≠ Closed Won، Stage ≠ Closed Lost
* **الفرز**: Close Date تصاعديًا
## Working with Opportunities
## العمل مع الفرص
### Creating Opportunities
### إنشاء الفرص
* Click **+ New** in the Opportunities view
* Or click **+** in a specific stage column
* انقر على **+ New** في عرض الفرص
* أو انقر على **+** في عمود مرحلة معيّنة
### Moving Through Stages
### الانتقال عبر المراحل
Drag and drop opportunity cards between columns to update their stage.
اسحب وأفلِت بطاقات الفرص بين الأعمدة لتحديث مرحلتها.
<VimeoEmbed videoId="927888627" title="Video demonstration" />
<VimeoEmbed videoId="927888627" title="عرض توضيحي بالفيديو" />
## أفضل الممارسات
### Pipeline Hygiene
### نظافة مسار المبيعات
* Update deals daily as they progress
* Move or close stale deals promptly
* Keep close dates realistic
* حدِّث الصفقات يوميًا مع تقدّمها
* انقل الصفقات الراكدة أو أغلِقها على الفور
* اجعل تواريخ الإقفال واقعية
### Stage Discipline
### الانضباط في المراحل
* Define clear criteria for each stage
* Move deals promptly when criteria are met
* Don't let deals sit in stages too long
* حدِّد معايير واضحة لكل مرحلة
* انقل الصفقات فور استيفاء المعايير
* لا تدَع الصفقات تبقى في المراحل لوقت طويل
## Related
## ذات صلة
* [Kanban Views](/l/ar/user-guide/views-pipelines/capabilities/kanban-views) — aggregations and compact view
* [Filters and Sorting](/l/ar/user-guide/views-pipelines/capabilities/filters-and-sorting) — creating filtered views
* [عروض كانبان](/l/ar/user-guide/views-pipelines/capabilities/kanban-views) — عمليات التجميع والعرض المضغوط
* [عوامل التصفية والفرز](/l/ar/user-guide/views-pipelines/capabilities/filters-and-sorting) — إنشاء عروض مُفلترة
@@ -1,66 +1,66 @@
---
title: Use Branches in Workflows
description: Understand how branches work and how to control which path is executed.
title: استخدام الفروع في سير العمل
description: افهم كيف تعمل الفروع وكيف تتحكم في المسار الذي يتم تنفيذه.
---
## How Branches Work
## كيف تعمل الفروع
In the workflow editor, you can create multiple paths (branches) going out from a single node. This allows you to build complex automations with different outcomes.
في محرر سير العمل، يمكنك إنشاء مسارات متعددة (فروع) تنطلق من عقدة واحدة. يُمكّنك هذا من إنشاء أتمتة معقدة بنتائج مختلفة.
**Important**: When a workflow runs, **all branches execute in parallel by default**. There is no built-in "if/else" logic to choose one branch over another—every path will run simultaneously.
**مهم**: عند تشغيل سير العمل، **تُنفَّذ جميع الفروع بالتوازي افتراضيًا**. لا توجد بنية منطقية مدمجة "if/else" لاختيار فرع على آخر — كل مسار سيعمل في الوقت نفسه.
## Controlling Which Branch Runs
## التحكم في الفرع الذي يعمل
To execute only one branch based on specific conditions, **add a Filter node at the beginning of each branch**.
لتنفيذ فرع واحد فقط بناءً على شروط محددة، **أضِف عقدة Filter في بداية كل فرع**.
### Example Setup
### مثال على الإعداد
1. Create your workflow with multiple branches from a single node
2. Add a **Filter** node as the first step in each branch
3. Set conditions on each Filter to determine when that branch should continue
4. Only the branch(es) whose Filter conditions are met will proceed
1. أنشئ سير العمل الخاص بك بفروع متعددة من عقدة واحدة
2. أضِف عقدة **Filter** كأول خطوة في كل فرع
3. عيِّن شروطًا على كل Filter لتحديد متى يجب أن يواصل ذلك الفرع
4. سيتابع فقط الفرع أو الفروع التي تستوفي شروط Filter
<img src="/images/user-guide/workflows/branches-with-filters.png" style={{width:'100%'}} />
### How Filters Work
### كيف تعمل عُقد Filter
* If the Filter condition is **met**: The branch continues executing
* If the Filter condition is **not met**: The branch stops at the Filter node
* إذا كان شرط Filter **متحققًا**: يتابع الفرع التنفيذ
* إذا كان شرط Filter **غير متحقق**: يتوقف الفرع عند عقدة Filter
This effectively creates conditional logic where only the appropriate branch runs based on your data.
يُنشئ هذا عمليًا منطقًا شرطيًا بحيث لا يعمل إلا الفرع المناسب بناءً على بياناتك.
## Example: Route by Deal Size
## مثال: التوجيه حسب حجم الصفقة
**Scenario**: When a deal is closed, send different notifications based on deal size.
**السيناريو**: عند إغلاق صفقة، أرسِل إشعارات مختلفة حسب حجم الصفقة.
1. **Trigger**: Opportunity updated (Stage = Closed Won)
2. **Branch 1**: Filter for Amount > $10,000 → Send Slack message to #big-deals
3. **Branch 2**: Filter for Amount ≤ $10,000 → Send email to sales manager
1. **المشغّل**: تم تحديث الفرصة (المرحلة = Closed Won)
2. **الفرع 1**: شرط Filter للمبلغ > $10,000 → إرسال رسالة Slack إلى #big-deals
3. **الفرع 2**: شرط Filter للمبلغ ≤ $10,000 → إرسال بريد إلكتروني إلى مدير المبيعات
Both branches start, but only the one matching the deal amount will continue past its Filter.
يبدأ الفرعان، لكن الفرع الذي يطابق مبلغ الصفقة فقط سيستمر بعد عقدة Filter.
## Creating Branches
## إنشاء الفروع
<Note>
To create a new branch from an existing step, click the **+** button on the step and add your action. You can add multiple branches by clicking **+** multiple times.
لإنشاء فرع جديد من خطوة موجودة، انقر زر **+** على الخطوة وأضِف الإجراء الخاص بك. يمكنك إضافة عدة فروع بالنقر على **+** عدة مرات.
</Note>
1. In the workflow editor, select the step you want to branch from
2. Click the **+** button to add an action
3. This creates one branch
4. Click **+** again on the same step to create additional branches
5. Each branch can have its own sequence of actions
1. في محرر سير العمل، حدِّد الخطوة التي تريد التفريع منها
2. انقر **+** لإضافة إجراء
3. سيؤدي هذا إلى إنشاء فرع واحد
4. انقر **+** مرة أخرى على نفس الخطوة لإنشاء فروع إضافية
5. يمكن لكل فرع أن يكون له تسلسل إجراءات خاص به
## Merging Branches Back Together
## دمج الفروع معًا مرة أخرى
After parallel branches complete their work, you can merge them back into a single path:
بعد أن تُكمل الفروع المتوازية عملها، يمكنك دمجها مرة أخرى في مسار واحد:
1. Complete your branched actions
2. Add a new step that should run after all branches
3. Drag a connection from the last step of each branch to this new step
4. The merged step waits for all connected branches to complete before executing
1. أكمل إجراءات الفروع
2. أضِف خطوة جديدة ينبغي أن تعمل بعد جميع الفروع
3. اسحب اتصالًا من الخطوة الأخيرة لكل فرع إلى هذه الخطوة الجديدة
4. تنتظر الخطوة المدمجة اكتمال جميع الفروع المتصلة قبل التنفيذ
### Example: Process Then Notify
### مثال: المعالجة ثم الإشعار
```
Trigger
@@ -74,17 +74,17 @@ Trigger
Merged Step: Send Confirmation Email
```
The confirmation email sends only after both the customer update and ticket creation are done.
لا يتم إرسال رسالة التأكيد عبر البريد الإلكتروني إلا بعد اكتمال تحديث العميل وإنشاء التذكرة.
## أفضل الممارسات
* Always use **Filter nodes** at the start of branches when you want conditional execution
* Keep branch conditions **mutually exclusive** to avoid duplicate actions
* Test your workflows with different data to ensure the correct branches run
* **Rename branch steps** descriptively so it's clear what each path does
* **Merge branches** when you need a final action after parallel processing
* استخدم دائمًا **عُقد Filter** في بداية الفروع عندما تريد تنفيذًا شرطيًا
* اجعل شروط الفروع **متبادلة الإقصاء** لتجنّب الإجراءات المكررة
* اختبر سير العمل لديك ببيانات مختلفة للتأكد من تشغيل الفروع الصحيحة
* **أعد تسمية خطوات الفروع** بطريقة وصفية ليكون واضحًا ما يفعله كل مسار
* **ادمج الفروع** عندما تحتاج إلى إجراء نهائي بعد المعالجة المتوازية
## Related
## ذات صلة
* [Workflows FAQ](/l/ar/user-guide/workflows/how-tos/need-more-help/workflows-faq) — answers about parallel execution
* [Workflow Actions](/l/ar/user-guide/workflows/capabilities/workflow-actions) — available actions for branches
* [الأسئلة الشائعة حول سير العمل](/l/ar/user-guide/workflows/how-tos/need-more-help/workflows-faq) — إجابات حول التنفيذ المتوازي
* [إجراءات سير العمل](/l/ar/user-guide/workflows/capabilities/workflow-actions) — الإجراءات المتاحة للفروع
@@ -6,10 +6,6 @@ image: /images/user-guide/workflows/workflow.png
Iterator lets you loop through an array of records and perform actions on each one. It's essential for workflows that need to process multiple records returned by Search Records or received via webhooks.
<Note>
Iterator is currently in beta. Activate it under **Settings → Releases → Lab**.
</Note>
## When to Use Iterator
| Scenario | مثال |
@@ -96,150 +96,150 @@ import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
* استخدم البيانات من الخطوات السابقة لملء الحقول
**How it works**:
**كيف يعمل**:
1. Searches for a record matching your criteria
2. If found → updates the existing record
3. If not found → creates a new record
1. يبحث عن سجل يطابق معاييرك
2. إذا تم العثور عليه → يحدّث السجل الموجود
3. إذا لم يُعثر عليه → ينشئ سجلًا جديدًا
**Output**: The created or updated record data is available for use in subsequent steps.
**المخرجات**: بيانات السجل التي تم إنشاؤها أو تحديثها متاحة للاستخدام في الخطوات التالية.
## Flow Actions
## إجراءات التدفق
### مكرر
**Loops through an array of records** returned from a previous step, allowing you to perform actions on each record individually.
**يتكرر عبر مصفوفة من السجلات** المُعادة من خطوة سابقة، مما يتيح لك تنفيذ إجراءات على كل سجل بشكل فردي.
**التكوين**:
* Select the array of records from a previous step (e.g., results from Search Records, from a Manual trigger with Bulk availability, from a code node)
* اختر مصفوفة السجلات من خطوة سابقة (مثل نتائج البحث عن السجلات، أو من مشغل يدوي مع إتاحة التنفيذ بالجملة، أو من عقدة كود)
* حدد الإجراءات لتنفيذها على كل سجل في الحلقة.
<Note>
- You can add several actions within an iterator.
- When using branches inside an iterator, make sure the last step of each branch connects back to the iterator to close the loop.
- يمكنك إضافة عدة إجراءات داخل المُكرِّر.
- عند استخدام تفرعات داخل المُكرِّر، تأكد من أن تتصل الخطوة الأخيرة من كل تفرع بالمُكرِّر لإغلاق الحلقة.
</Note>
* Access `Current Item` Fields: to use fields from the record currently being processed, click on the **Iterator** step, then select **Current item**. The list of available fields from that record will be displayed and can be selected for use in subsequent actions.
* الوصول إلى حقول `Current Item`: لاستخدام حقول السجل الجاري معالجته، انقر على خطوة **المُكرِّر**، ثم اختر **العنصر الحالي**. ستُعرَض قائمة الحقول المتاحة من ذلك السجل ويمكن اختيارها لاستخدامها في الإجراءات اللاحقة.
<VimeoEmbed videoId="1146577247" title="Video demonstration" />
<VimeoEmbed videoId="1146577247" title="عرض توضيحي بالفيديو" />
### تصفية
Filters records based on specified conditions, allowing only records that meet the criteria to pass through.
يقوم بتصفية السجلات بناءً على الشروط المحددة، مما يسمح فقط للسجلات التي تلبي المعايير بالمرور.
**التكوين**:
* Select the record to filter
* اختر السجل لتصفيته
* حدد شروط ومعايير التصفية
* قم بتكوين السجلات التي يجب أن تمر إلى الخطوات اللاحقة
<Note>
1. **Output**: Filter nodes don't return data—they act as gates. If the conditions are met, the workflow continues. If not, the workflow stops at that branch.
2. The `IS` operator can be used with numeric fields. It performs as an `EQUAL`.
1. **المخرجات**: عُقد التصفية لا تُرجِع بيانات — فهي تعمل كبوابات. إذا تم استيفاء الشروط، يتابع سير العمل. وإلا سيتوقف سير العمل عند ذلك الفرع.
2. يمكن استخدام العامل `IS` مع الحقول الرقمية. يعمل كأنه `EQUAL`.
</Note>
### Delay
### التأخير
Pauses workflow execution for a specified duration or until a specific date/time.
يُوقف تنفيذ سير العمل لمدة محددة أو حتى تاريخ/وقت معين.
**Delay Types**:
**أنواع التأخير**:
| النوع | الوصف |
| ------------------ | ------------------------------------------------------------------ |
| **Duration** | Wait for a specific amount of time (days, hours, minutes, seconds) |
| **Scheduled Date** | Wait until a specific date and time |
| النوع | الوصف |
| ---------------- | ----------------------------------------------------- |
| **المدة** | الانتظار لمدة زمنية محددة (أيام، ساعات، دقائق، ثوانٍ) |
| **تاريخ مُجدول** | الانتظار حتى تاريخ ووقت محددين |
**Configuration for Duration**:
**إعدادات المدة**:
* Set days, hours, minutes, and/or seconds
* Combine multiple units (e.g., 2 days and 4 hours)
* تعيين الأيام والساعات والدقائق و/أو الثواني
* دمج وحدات متعددة (مثل يومين و4 ساعات)
**Configuration for Scheduled Date**:
**إعدادات التاريخ المُجدول**:
* Select a date and time
* Can reference a date field from a previous step (e.g., follow up 3 days after a meeting)
* اختر تاريخًا ووقتًا
* يمكن الإشارة إلى حقل تاريخ من خطوة سابقة (مثل المتابعة بعد 3 أيام من اجتماع)
**حالات الاستخدام**:
* Wait 24 hours before sending a follow-up email
* Pause until an opportunity's close date
* Schedule actions for business hours
* انتظر 24 ساعة قبل إرسال بريد متابعة إلكتروني
* إيقاف مؤقت حتى تاريخ إغلاق الفرصة
* جدولة الإجراءات ضمن ساعات العمل
<Note>
The scheduled date cannot be in the past. If a date field from a previous step is used and the date has already passed, the workflow will fail.
لا يمكن أن يكون التاريخ المُجدول في الماضي. إذا استُخدم حقل تاريخ من خطوة سابقة وكان التاريخ قد مضى بالفعل، فسيفشل سير العمل.
</Note>
**Limits & Credits**:
**الحدود والرصيد**:
* **No maximum duration limit**—you can set delays of minutes, days, weeks, or longer
* **1 credit consumed** when the Delay node executes, regardless of duration
* **No credits consumed** while waiting—a 5-minute delay costs the same as a 5-day delay
* **لا يوجد حد أقصى للمدة** — يمكنك تعيين تأخيرات بالدقائق أو الأيام أو الأسابيع أو أكثر
* **يُستهلَك رصيد واحد** عند تنفيذ عقدة التأخير، بغض النظر عن المدة
* **لا يُستهلك أي رصيد** أثناء الانتظار — تأخير 5 دقائق يكلف مثل تأخير 5 أيام
## Communication Actions
## إجراءات الاتصال
### إرسال البريد الإلكتروني
يرسل بريدًا إلكترونيًا من سير العمل الخاص بك. This is great for templated group emails. Emails will look like the ones you send from your mailbox.
Not suited for newsletters (which require richer formatting) or automated email sequences.
يرسل بريدًا إلكترونيًا من سير العمل الخاص بك. هذا رائع لرسائل البريد الجماعية المعتمدة على قوالب. ستبدو رسائل البريد الإلكتروني مثل تلك التي ترسلها من صندوق بريدك.
غير مناسب للرسائل الإخبارية (التي تتطلب تنسيقًا أغنى) أو سلاسل الرسائل الإلكترونية المؤتمتة.
**Prerequisites**: Add an email account in Settings → Accounts
**المتطلبات الأساسية**: أضف حساب بريد إلكتروني في الإعدادات → الحسابات
**التكوين**:
* Select the sender email account
* اختر حساب البريد الإلكتروني المُرسل
<Note>
You can only send emails from mailboxes synced to your own Twenty account. Sending from other team members' mailboxes (e.g., the account owner's email) is on the roadmap.
يمكنك إرسال رسائل البريد الإلكتروني فقط من صناديق بريد متزامنة مع حساب Twenty الخاص بك. إرسال الرسائل من صناديق بريد أعضاء الفريق الآخرين (مثل بريد مالك الحساب) ضمن الخطة المستقبلية.
</Note>
For all the following steps, you can reference variables from previous steps for personalization.
في جميع الخطوات التالية، يمكنك الرجوع إلى متغيرات من الخطوات السابقة لأغراض التخصيص.
* ادخل عنوان البريد الإلكتروني المستلم.
<Note>
Only one recipient is possible at the moment.
حاليًا يمكن اختيار مستلم واحد فقط.
</Note>
* اضبط سطر الموضوع.
* قم بإنشاء نص الرسالة. You can format links, create numbered list, bullet point lists, add attachments.
* قم بإنشاء نص الرسالة. يمكنك تنسيق الروابط، وإنشاء قوائم مرقمة، وقوائم نقطية، وإضافة مرفقات.
<Note>
Adding HTML signatures is not possible at the moment.
إضافة توقيعات HTML غير ممكنة في الوقت الحالي.
</Note>
### نموذج
يعرض نموذجاً أثناء تنفيذ سير العمل لجمع مدخلات المستخدم. The responses can then be used in subsequent steps to create records, send emails, or execute any other action based on the input.
يعرض نموذجاً أثناء تنفيذ سير العمل لجمع مدخلات المستخدم. يمكن بعد ذلك استخدام الردود في الخطوات اللاحقة لإنشاء سجلات أو إرسال رسائل بريد إلكتروني أو تنفيذ أي إجراء آخر بناءً على المُدخل.
<Warning>
**Forms are designed for manual triggers only**. بالنسبة لمهام سير العمل مع محركات أخرى (سجل تم إنشاؤه، تم تحديثه، إلخ)، يمكن الوصول إلى النماذج فقط من خلال واجهة تشغيل سير العمل، وهو ليس التجربة المتوقعة. سيتم إصدار مركز الإشعارات في عام 2026 لدعم النماذج في مهام سير العمل المؤتمتة بشكل صحيح.
**تم تصميم النماذج للمشغلات اليدوية فقط**. بالنسبة لمهام سير العمل مع محركات أخرى (سجل تم إنشاؤه، تم تحديثه، إلخ)، يمكن الوصول إلى النماذج فقط من خلال واجهة تشغيل سير العمل، وهو ليس التجربة المتوقعة. سيتم إصدار مركز الإشعارات في عام 2026 لدعم النماذج في مهام سير العمل المؤتمتة بشكل صحيح.
</Warning>
**التكوين**:
* Configure the fields that users will be asked to fill. For each field, choose
* a type among text, number, date, a given record, a select field. Select fields from all objects are available.
* a label
* a default value under `Placeholder` (optional)
* Edit the form title
* قم بتهيئة الحقول التي سيُطلب من المستخدمين تعبئتها. لكل حقل، اختر
* نوعًا من بين: نص، رقم، تاريخ، سجل مُعطى، حقل اختيار. حقول الاختيار من جميع الكائنات متاحة.
* تسمية
* قيمة افتراضية ضمن `Placeholder` (اختياري)
* حرّر عنوان النموذج
**المخرجات**: استجابات النموذج متاحة للاستخدام في الخطوات اللاحقة.
**Example**: The "Quick Lead" workflow is available by default in all workspaces, available anywhere in the Command Menu `Cmd + K`.
**مثال**: يتوفر سير العمل "Quick Lead" افتراضيًا في جميع مساحات العمل، وهو متاح في أي مكان ضمن قائمة الأوامر `Cmd + K`.
**How to fill the form**:
**كيفية تعبئة النموذج**:
* Trigger your manual workflow from the command menu `Cmd K`
* Fill the form that is displayed in the side panel and click `Submit`.
* شغّل سير العمل اليدوي من قائمة الأوامر `Cmd K`
* املأ النموذج المعروض في اللوحة الجانبية ثم انقر `Submit`.
<Note>
The fields cannot be made mandatory.
لا يمكن جعل الحقول إلزامية.
</Note>
<VimeoEmbed videoId="1147277989" title="Video demonstration" />
<VimeoEmbed videoId="1147277989" title="عرض توضيحي بالفيديو" />
## Integration Actions
## إجراءات التكامل
### كود
@@ -247,24 +247,24 @@ For all the following steps, you can reference variables from previous steps for
**التكوين**:
* الوصول إلى المتغيرات من الخطوات السابقة. You can edit the variables names dynamically.
* الوصول إلى المتغيرات من الخطوات السابقة. يمكنك تعديل أسماء المتغيرات ديناميكيًا.
<VimeoEmbed videoId="1147281795" title="Video demonstration" />
<VimeoEmbed videoId="1147281795" title="عرض توضيحي بالفيديو" />
* اكتب شيفرة جافا سكريبت في المحرر
* إرجاع المتغيرات للاستخدام في الخطوات اللاحقة
* اختبر الكود مباشرة في الخطوة
<Note>
If you need to use external API keys in your code, you must input them directly in the function body. You cannot configure API keys elsewhere and reference them in the serverless function.
إذا كنت بحاجة إلى استخدام مفاتيح API خارجية في كودك، فيجب إدخالها مباشرةً في جسم الدالة. لا يمكنك تكوين مفاتيح API في مكان آخر والإشارة إليها في الدالة عديمة الخادم.
</Note>
<Tip>
**Working with arrays?** Arrays from external systems or previous steps may come as strings. See [How to handle arrays in Code actions](/l/ar/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions) for the solution.
**هل تعمل مع المصفوفات؟** قد تأتي المصفوفات من أنظمة خارجية أو من خطوات سابقة على هيئة سلاسل نصية. راجع [كيفية التعامل مع المصفوفات في إجراءات Code](/l/ar/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions) للحل.
</Tip>
<Tip>
Click the square icon at the top right of the code editor to display it in full screen — helpful since the default editor width is limited.
انقر على أيقونة المربع في أعلى يمين محرر الكود لعرضه بملء الشاشة — فهذا مفيد لأن عرض المحرر الافتراضي محدود.
</Tip>
### طلب HTTP
@@ -275,37 +275,37 @@ For all the following steps, you can reference variables from previous steps for
**التكوين**:
* ادخل عنوان رابط واجهة برمجية. Using parameters from previous steps is possible.
* ادخل عنوان رابط واجهة برمجية. يمكن استخدام معاملات من خطوات سابقة.
* اختر طريقة HTTP (GET, POST, PUT, PATCH, DELETE)
* أضف الرؤوس والقيم المطلوبة
* قدّم مثالًا للمخرجات لمعاينة البنية
## AI Actions
## إجراءات الذكاء الاصطناعي
### AI Agent - Coming Soon
### وكيل ذكاء اصطناعي - قريبًا
Runs an AI agent within your workflow to perform intelligent tasks.
يشغّل وكيل ذكاء اصطناعي داخل سير العمل لديك لتنفيذ مهام ذكية.
**التكوين**:
* **Agent**: Select an existing AI agent or use the default agent
* **Prompt**: Write the instruction for the AI agent
* Reference variables from previous steps in the prompt
* **الوكيل**: اختر وكيلاً للذكاء الاصطناعي موجودًا أو استخدم الوكيل الافتراضي
* **المطالبة**: اكتب التعليمات لوكيل الذكاء الاصطناعي
* ارجع إلى متغيرات من خطوات سابقة داخل المطالبة
**What AI Agents can do**:
**ما الذي يمكن لوكلاء الذكاء الاصطناعي فعله**:
* Analyze and summarize data
* Classify or categorize records
* Generate text content
* Make decisions based on data
* Interact with your CRM data using tools
* تحليل البيانات وتلخيصها
* تصنيف السجلات أو توزيعها ضمن فئات
* إنشاء محتوى نصي
* اتخاذ قرارات بناءً على البيانات
* التفاعل مع بيانات نظام إدارة علاقات العملاء لديك باستخدام الأدوات
**Output**: The AI agent's response is available for use in subsequent steps. If the agent has a structured output schema, the response will follow that format.
**المخرجات**: رد وكيل الذكاء الاصطناعي متاح للاستخدام في الخطوات التالية. إذا كان للوكيل مخطط مخرجات مُهيكل، فسيتبع الرد ذلك التنسيق.
<Note>
AI Agent actions consume workflow credits based on the AI model used. See [Workflow Credits](/l/ar/user-guide/workflows/capabilities/workflow-credits) for details.
تستهلك إجراءات وكيل الذكاء الاصطناعي أرصدة سير العمل بناءً على نموذج الذكاء الاصطناعي المستخدم. راجع [أرصدة سير العمل](/l/ar/user-guide/workflows/capabilities/workflow-credits) للحصول على التفاصيل.
</Note>
<Note>
AI agents respect role-based permissions. You can assign specific roles to agents under **Settings → Roles** to control what data they can access. See [Permissions](/l/ar/user-guide/permissions-access/capabilities/permissions) for details.
يحترم وكلاء الذكاء الاصطناعي الأذونات المستندة إلى الأدوار. يمكنك تعيين أدوار محددة للوكلاء ضمن **الإعدادات → الأدوار** للتحكم في البيانات التي يمكنهم الوصول إليها. راجع [الأذونات](/l/ar/user-guide/permissions-access/capabilities/permissions) للحصول على التفاصيل.
</Note>
@@ -1,23 +1,23 @@
---
title: محفزات سير العمل
description: Learn about the different triggers that start your workflows.
description: تعرّف على المحفزات المختلفة التي تُشغِّل سير العمل لديك.
---
## About Triggers
## حول المحفزات
تبدأ سير العمل دائمًا بمحفز واحد يحدد متى ينبغي تشغيل الأتمتة.
<img src="/images/user-guide/workflows/workflow_triggers.png" style={{width:'100%'}} />
<Tip>
**Advanced objects are supported!** Beyond standard CRM objects (People, Companies, Opportunities), you can also trigger workflows and perform actions on:
**الكائنات المتقدمة مدعومة!** إلى جانب كائنات CRM القياسية (الأشخاص، الشركات، الفرص)، يمكنك أيضًا تشغيل سير العمل وتنفيذ إجراءات على:
* أعضاء مساحة العمل
* Calendar Events
* Messages (Emails)
* Tasks, Notes, and many other system objects
* أحداث التقويم
* الرسائل (رسائل البريد الإلكتروني)
* المهام، والملاحظات، والعديد من كائنات النظام الأخرى
This opens up powerful automations like notifying team members when calendar events are created, or processing incoming emails automatically.
يفتح هذا المجال لأتمتة قوية مثل إشعار أعضاء الفريق عند إنشاء أحداث التقويم، أو معالجة رسائل البريد الإلكتروني الواردة تلقائيًا.
</Tip>
## إنشاء سجل
@@ -27,9 +27,9 @@ description: Learn about the different triggers that start your workflows.
**التكوين**: حدد نوع الكائن لمراقبة السجلات الجديدة.
<Note>
* This trigger is great for records created by csv, mailbox and calendar synchronization, API.
* **It is not recommended for records created manually**: with this trigger, workflows start as soon as the record is created. Since Twenty UI offers auto-save on the fly (there is not an edit mode and then a validation to save records), the workflow will be triggered before the user inputs all the fields.
To trigger this workflow on records created manually, it is recommended to use the trigger `Record is created or updated` instead.
* هذا المحفز رائع للسجلات التي يتم إنشاؤها عبر CSV، ومزامنة صندوق البريد والتقويم، وواجهة برمجة التطبيقات (API).
* **لا يُنصح به للسجلات التي تُنشأ يدويًا**: مع هذا المحفز، تبدأ عمليات سير العمل فور إنشاء السجل. نظرًا لأن Twenty UI تتيح الحفظ التلقائي أثناء العمل (لا توجد وضعية تحرير ثم تحقق لحفظ السجلات)، فسيتم تشغيل سير العمل قبل أن يُدخل المستخدم جميع الحقول.
لتشغيل سير العمل هذا على السجلات التي تم إنشاؤها يدويًا، يُوصى باستخدام المحفز `Record is created or updated` بدلًا من ذلك.
</Note>
## تحديث السجل
@@ -62,27 +62,27 @@ description: Learn about the different triggers that start your workflows.
**التكوين**: حدد نوع الكائن لمراقبة عمليات الحذف.
## Manual Trigger
## المحفز اليدوي
يبدأ سير العمل عندما يتم تشغيله بواسطة إجراء المستخدم. This trigger can be accessed through the `Cmd+K` menu or via a custom button that will be displayed in the top navbar after selecting record(s).
يبدأ سير العمل عندما يتم تشغيله بواسطة إجراء المستخدم. يمكن الوصول إلى هذا المحفز من خلال قائمة `Cmd+K` أو عبر زر مخصص سيُعرض في شريط التنقل العلوي بعد تحديد سجل/سجلات.
<img src="/images/user-guide/workflows/add_to_newsletter_button.png" style={{width:'100%'}} />
**إعداد التوفر**:
اختر كيفية التعامل مع تحديد السجل في سير العمل:
* **العالمي**: لا يتطلب أي سجل لتشغيل سير العمل هذا. The workflow is triggered from the command menu `Cmd + K` anywhere (from any object) and does not use record(s) as input.
* **العالمي**: لا يتطلب أي سجل لتشغيل سير العمل هذا. يتم تشغيل سير العمل من قائمة الأوامر `Cmd + K` من أي مكان (من أي كائن) ولا يستخدم سجل/سجلات كمدخل.
* **مفرد**: سيتم تمرير السجل (السجلات) المحددة إلى سير العمل الخاص بك. تم تكوين هذا لكائن معين. يمكن اختيار عدة سجلات قبل إطلاق سير العمل. The workflow will run from beginning to end as many times as there are records selected.
* **مفرد**: سيتم تمرير السجل (السجلات) المحددة إلى سير العمل الخاص بك. تم تكوين هذا لكائن معين. يمكن اختيار عدة سجلات قبل إطلاق سير العمل. سوف يعمل سير العمل من البداية إلى النهاية بعدد مرات يساوي عدد السجلات المحددة.
<Note>
**Soft limit: 100 runs/minute**. Beyond this, workflows remain in "Not Started" status and are processed gradually—either by a background job or when another workflow enters the queue. This means you can select more than 100 records with a Single trigger; execution will just be slower.
**حد مرن: 100 عملية تشغيل/دقيقة**. بعد ذلك، تظل عمليات سير العمل في حالة "Not Started" ويتم معالجتها تدريجيًا—إما بواسطة مهمة خلفية أو عندما يدخل سير عمل آخر قائمة الانتظار. هذا يعني أنه يمكنك تحديد أكثر من 100 سجل باستخدام محفز واحد؛ ستكون عملية التنفيذ أبطأ فقط.
</Note>
* **الاختيار الشامل**: سيتم تمرير السجل/السجلات المحددة إلى سير العمل الخاص بك. تم تكوين هذا لكائن معين. يمكن اختيار عدة سجلات قبل إطلاق سير العمل. سيتم تشغيل سير العمل مرة واحدة، مما يوفر القائمة الكاملة للسجلات كمدخلات. This means the workflow needs to contain an [Iterator action](/l/ar/user-guide/workflows/capabilities/workflow-actions#iterator).
* **الاختيار الشامل**: سيتم تمرير السجل/السجلات المحددة إلى سير العمل الخاص بك. تم تكوين هذا لكائن معين. يمكن اختيار عدة سجلات قبل إطلاق سير العمل. سيتم تشغيل سير العمل مرة واحدة، مما يوفر القائمة الكاملة للسجلات كمدخلات. هذا يعني أن سير العمل يحتاج إلى احتواء [إجراء المُكرِّر](/l/ar/user-guide/workflows/capabilities/workflow-actions#iterator).
<Note>
This is more advanced, and best for people who want to optimize the number of workflow runs.
هذا أكثر تقدمًا، وهو الأفضل لمن يرغبون في تحسين عدد مرات تشغيل سير العمل.
</Note>
<img src="/images/user-guide/workflows/manual_trigger.png" style={{width:'100%'}} />
@@ -95,10 +95,10 @@ description: Learn about the different triggers that start your workflows.
**طرق الوصول**:
* `Cmd+K` menu to find and launch manual workflows
* قائمة `Cmd+K` للعثور على وتشغيل عمليات سير العمل اليدوية
* زر مخصص في شريط التنقل العلوي (إذا تم تكوينه)
## Time-Based Trigger: On a Schedule
## محفز قائم على الوقت: وفق جدول زمني
يبدأ سير العمل على أساس دوري تحدده.
@@ -108,10 +108,10 @@ description: Learn about the different triggers that start your workflows.
* أدخل قيمة أو استخدم تعبيرات كرون مخصصة للجدولة المتقدمة
<Note>
**Timezone**: Scheduled workflows run in **UTC**. When setting hours for daily schedules, convert your local time to UTC.
**المنطقة الزمنية**: تعمل عمليات سير العمل المجدولة وفق **UTC**. عند تعيين الساعات للجداول اليومية، حوّل وقتك المحلي إلى UTC.
</Note>
## External Trigger: Webhook
## محفز خارجي: ويب هوك
يبدأ سير العمل عندما يتم استقبال طلب GET أو POST من خدمة خارجية.
@@ -119,18 +119,18 @@ description: Learn about the different triggers that start your workflows.
**التكوين**:
* The workflow provides a unique webhook URL—copy this and add it to your external system as the endpoint to call.
* For POST requests, define the expected body structure so Twenty knows what data to expect. Add here the fields you will receive that will be needed below in your workflow.
* Configure authentication (coming soon).
* يوفر سير العمل عنوان URL فريدًا لويب هوك—انسخه وأضفه إلى نظامك الخارجي كنقطة نهاية للاستدعاء.
* بالنسبة لطلبات POST، حدِّد البنية المتوقعة لمحتوى الطلب حتى يعرف Twenty ما البيانات المتوقع تلقيها. أضف هنا الحقول التي ستستلمها والتي ستكون مطلوبة أدناه في سير العمل لديك.
* قم بتكوين المصادقة (قريبًا).
## Choosing the Right Trigger
## اختيار المحفز المناسب
| Use Case | Recommended Trigger |
| --------------------------- | ------------------------ |
| New leads need processing | إنشاء سجل |
| Data changes need sync | تحديث السجل |
| Import/manual data handling | تحديث أو إنشاء سجل |
| Cleanup after deletion | حذف السجل |
| User-initiated action | التشغيل يدويًا |
| Recurring reports | بجدول زمني |
| External integration | Webhook or On a Schedule |
| حالة الاستخدام | المحفز الموصى به |
| ------------------------------------------ | ------------------------ |
| العملاء المحتملون الجدد يحتاجون إلى معالجة | إنشاء سجل |
| تغييرات البيانات تحتاج إلى مزامنة | تحديث السجل |
| استيراد/معالجة البيانات يدويًا | تحديث أو إنشاء سجل |
| التنظيف بعد الحذف | حذف السجل |
| إجراء يبدأه المستخدم | التشغيل يدويًا |
| تقارير متكررة | بجدول زمني |
| تكامل خارجي | ويب هوك أو وفق جدول زمني |
@@ -1,56 +1,56 @@
---
title: Detect Stale Opportunities
description: Automatically notify managers when opportunities haven't been updated.
title: اكتشاف الفرص الراكدة
description: إخطار المديرين تلقائيًا عند عدم تحديث الفرص.
---
Keep your pipeline healthy by alerting managers when opportunities go stale. This workflow checks for opportunities that haven't been updated in a specified number of days.
حافظ على صحة خط أنابيب المبيعات من خلال تنبيه المديرين عندما تصبح الفرص راكدة. يتحقق سير العمل هذا من الفرص التي لم يتم تحديثها خلال عدد محدد من الأيام.
## The Problem
## المشكلة
Opportunities sitting without updates lead to:
الفرص التي تبقى دون تحديث تؤدي إلى:
* Deals going cold
* Unreliable forecasts
* Lost revenue
* فتور الصفقات
* توقعات غير موثوقة
* إيرادات مفقودة
## The Solution
## الحل
Create a scheduled workflow that finds stale opportunities and emails their managers.
أنشئ سير عملًا مُجدولًا يعثر على الفرص الراكدة ويرسل بريدًا إلكترونيًا إلى مديريها.
## Step-by-Step Setup
## إعداد خطوة بخطوة
### Step 1: Create the Workflow
### الخطوة 1: إنشاء سير العمل
1. Go to **Settings → Workflows**
2. Click **+ New Workflow**
3. Name it "Stale Opportunity Alert"
1. اذهب إلى **الإعدادات → سير العمل**
2. انقر **+ سير عمل جديد**
3. قم بتسميته "تنبيه الفرص الراكدة"
### Step 2: Configure the Trigger
### الخطوة 2: تهيئة المشغّل
1. Select **On a Schedule**
2. Set to run daily (e.g., every day at 8 AM)
1. حدد **وفق جدول**
2. عيّن التشغيل يوميًا (مثلاً، كل يوم الساعة 8 صباحًا)
### Step 3: Search for Stale Opportunities
### الخطوة 3: البحث عن الفرص الراكدة
1. Add **Search Records** action
2. Configure:
1. أضف إجراء **Search Records**
2. التكوين:
| الحقل | القيمة |
| ---------- | ----------------------------------------------- |
| **Object** | الفرص |
| **Filter** | Updated At is before (today - 7 days) |
| **Filter** | Stage is not "Closed Won" AND not "Closed Lost" |
| **Limit** | 100 |
| الحقل | القيمة |
| ---------- | ------------------------------------------- |
| **الكائن** | الفرص |
| **تصفية** | Updated At قبل (اليوم - 7 أيام) |
| **تصفية** | المرحلة ليست "Closed Won" ولا "Closed Lost" |
| **الحد** | 100 |
### Step 4: Check If Any Found
### الخطوة 4: التحقق مما إذا تم العثور على أي عناصر
1. Add **Filter** action
2. Condition: `{{searchRecords.length}}` is greater than 0
3. If no stale opportunities, the workflow stops here
1. أضف إجراء **تصفية**
2. الشرط: `{{searchRecords.length}}` أكبر من 0
3. إذا لم توجد فرص راكدة، يتوقف سير العمل هنا
### Step 5: Format the Alert (Code Action)
### الخطوة 5: تنسيق التنبيه (إجراء Code)
Add a **Code** action to format the email:
أضف إجراء **Code** لتنسيق البريد الإلكتروني:
```javascript
export const main = async (params) => {
@@ -88,49 +88,49 @@ export const main = async (params) => {
};
```
### Step 6: Send Alert Email
### الخطوة 6: إرسال بريد التنبيه
Add **Send Email** action:
أضف إجراء **Send Email**:
| الحقل | القيمة |
| ----------- | ----------------------------------------------------------- |
| **To** | sales-manager@yourcompany.com |
| **Subject** | `🚨 {{code.totalCount}} Stale Opportunities Need Attention` |
| **Body** | `{{code.summary}}` |
| الحقل | القيمة |
| ----------- | --------------------------------------------------- |
| **إلى** | sales-manager@yourcompany.com |
| **الموضوع** | `🚨 {{code.totalCount}} فرص راكدة تحتاج إلى اهتمام` |
| **المحتوى** | `{{code.summary}}` |
### Step 7: Test and Activate
### الخطوة 7: الاختبار والتفعيل
1. Click **Test** to run the workflow
2. Check that the email contains the right data
3. Activate when ready
1. انقر **Test** لتشغيل سير العمل
2. تحقق من أن البريد الإلكتروني يحتوي على البيانات الصحيحة
3. فعّل عند الجاهزية
## Customization Options
## خيارات التخصيص
### Change Staleness Threshold
### تغيير عتبة الركود
Modify the Search Records filter to change from 7 days to your preferred period:
عدّل عامل تصفية Search Records لتغيير 7 أيام إلى الفترة التي تفضّلها:
* 3 days for high-velocity sales
* 14 days for enterprise deals
* 30 days for long sales cycles
* 3 أيام للمبيعات سريعة الوتيرة
* 14 يومًا لصفقات المؤسسات
* 30 يومًا لدورات المبيعات الطويلة
### Alert Individual Reps
### تنبيه المندوبين بشكل فردي
Instead of one manager email, use **Iterator** to send personalized emails to each rep about their own stale deals.
بدلًا من بريد مدير واحد، استخدم **Iterator** لإرسال رسائل مخصصة إلى كل مندوب حول صفقاته الراكدة.
### Add Escalation
### إضافة تصعيد
Create multiple workflows with increasing severity:
أنشئ عدة سير عمل بتدرّج في الشدة:
1. Day 7: Email to rep
2. Day 14: Email to rep + manager
3. Day 21: Create task for manager to intervene
1. اليوم 7: بريد إلى المندوب
2. اليوم 14: بريد إلى المندوب + المدير
3. اليوم 21: إنشاء مهمة للمدير للتدخل
### Include in Slack
### التضمين في Slack
Use **HTTP Request** to post to a Slack webhook instead of or in addition to email.
استخدم **HTTP Request** للنشر إلى Slack webhook بدلًا من البريد الإلكتروني أو بالإضافة إليه.
## Related
## ذات صلة
* [Workflow Actions](/l/ar/user-guide/workflows/capabilities/workflow-actions)
* [Send Emails from Workflows](/l/ar/user-guide/workflows/capabilities/send-emails-from-workflows)
* [إجراءات سير العمل](/l/ar/user-guide/workflows/capabilities/workflow-actions)
* [إرسال رسائل البريد الإلكتروني من سير العمل](/l/ar/user-guide/workflows/capabilities/send-emails-from-workflows)
@@ -0,0 +1,127 @@
---
title: Notify Teammates of a Note to Review
description: Send automatic email notifications when assigning a colleague to review a note.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<Note>
**Tagging teammates directly in notes is not yet supported.** This feature is planned for the second half of 2026. In the meantime, this workflow provides a practical workaround.
</Note>
## The Challenge
You want to tag a colleague in a note so they receive a notification to review it. Today, Twenty doesn't support @mentions in notes or tasks.
## The Workaround
Instead of tagging in the note text, you can:
1. Create a **Reviewer** relation field on the Notes object
2. Assign the reviewer when creating or editing the note
3. A workflow automatically sends an email to the reviewer with a link to the note
<Warning>
**Limitation**: This approach allows assigning one reviewer per field. If you need to notify multiple people, create additional relation fields (e.g., Reviewer 1, Reviewer 2). This won't scale well if you need to tag many collaborators at once.
</Warning>
## إعداد خطوة بخطوة
### Step 1: Create the Reviewer Field
<img src="/images/user-guide/workflows/reviewer-field-for-note.png" style={{width:'100%'}} />
1. Go to **Settings → Data Model → Notes**
2. Click **Add Field**
3. Configure:
| الإعداد | القيمة |
| ------------------ | --------------------------------- |
| **Name** | Reviewer |
| **النوع** | علاقة |
| **Related Object** | عضو في مساحة العمل |
| **Relation Type** | Many Notes → One Workspace Member |
4. Save the field
### الخطوة 2: إنشاء سير العمل
<VimeoEmbed videoId="1151897168" title="عرض توضيحي بالفيديو" />
#### Create the Workflow Trigger
1. Go to the main view and create a new workflow
2. Select **Record Updated** as the trigger
3. Choose **Note** as the object and specify the Reviewer field.
4. This will trigger whenever the reviewer of a note is updated.
#### Add a Filter to Check Reviewer Was Just Assigned
Add a **Filter** action to ensure the workflow only continues when a reviewer is assigned:
| Condition | القيمة |
| ------------ | -------- |
| **Reviewer** | غير فارغ |
#### Search for the Workspace Member
1. Add a **Search Records** action
2. Select **Workspace Member** (under Advanced Objects)
3. Add a filter:
| Condition | القيمة |
| --------- | ---------------------------- |
| **ID** | equals `{{note.reviewerId}}` |
This retrieves the full workspace member record, including their email address and name.
#### Send the Notification Email
1. Add a **Send Email** action
2. Configure:
| الحقل | القيمة |
| ----------- | --------------------------------------------------- |
| **إلى** | Search Record → First Workspace Member → User Email |
| **الموضوع** | A note needs your review |
| **المحتوى** | See example below |
**Email body example:**
```text
Hi {{searchRecord.firstWorkspaceMember.name.firstName}},
You've been assigned to review a note.
View the note here:
https://yourSubDomain.twenty.com/object/note/{{recordIsUpdated.id}}
Best,
Twenty
```
<Note>
Replace `yourSubDomain` with your actual Twenty workspace subdomain.
</Note>
#### Test and Activate
1. Click **Test** to run the workflow manually
2. Create or edit a note and assign a reviewer
3. Check the reviewer's inbox for the notification email
4. Activate the workflow
## استخدام
Once set up, your team can use this workflow by:
1. Creating a new note (or editing an existing one)
2. Selecting a colleague in the **Reviewer** field
3. The colleague automatically receives an email with a direct link to the note
## ذات صلة
* [مشغلات سير العمل](/l/ar/user-guide/workflows/capabilities/workflow-triggers)
* [Send Emails from Workflows](/l/ar/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Create Custom Fields](/l/ar/user-guide/data-model/how-tos/create-custom-fields)
* [Create Relation Fields](/l/ar/user-guide/data-model/how-tos/create-relation-fields)
@@ -1,170 +1,170 @@
---
title: استكشاف مشكلات سير العمل وإصلاحها
description: Common workflow issues and how to resolve them.
description: المشكلات الشائعة في سير العمل وكيفية حلّها.
---
## المشاكل الشائعة والحلول
### لم يتم تشغيل سير العمل
**Symptoms**: Your workflow doesn't run when you expect it to.
**الأعراض**: لا يعمل سير العمل كما تتوقع.
**Possible Causes**:
**الأسباب المحتملة**:
1. **Workflow not activated**: Ensure the workflow is set to "Active" not "Draft"
2. **Trigger conditions not met**: Verify the trigger matches your expected event
3. **Field not monitored**: For "Record is Updated" triggers, ensure the specific field is being watched
4. **Permissions**: Check you have permission to run workflows
1. **لم يتم تفعيل سير العمل**: تأكّد من تعيين سير العمل إلى "Active" وليس "Draft"
2. **شروط المُحفِّز غير مستوفاة**: تحقّق من أن المُحفِّز يطابق الحدث الذي تتوقعه
3. **حقل غير مُراقَب**: بالنسبة لمُحفِّزات "Record is Updated"، تأكّد من مراقبة الحقل المحدد
4. **الأذونات**: تحقّق من أن لديك الإذن لتشغيل سير العمل
**حلول**:
* Verify workflow status in the workflow list
* Test with the specific action you expect to trigger it
* Review trigger configuration
* Contact your admin about permissions
* تحقّق من حالة سير العمل في قائمة سير العمل
* اختبر بالإجراء المحدد الذي تتوقع أن يُشغِّله
* راجِع إعداد المُحفِّز
* تواصَل مع المسؤول لديك بشأن الأذونات
### Workflow Triggers Too Early (Empty Fields)
### مُحفِّزات سير العمل تعمل مبكراً جداً (حقول فارغة)
**Symptoms**: When manually creating a record in the UI, your workflow triggers before you've had time to fill in all the fields. The workflow runs with mostly empty field values.
**الأعراض**: عند إنشاء سجل يدوياً في واجهة المستخدم، يتم تشغيل سير العمل قبل أن تتمكّن من ملء جميع الحقول. يعمل سير العمل مع قيم حقول فارغة في الغالب.
**Why this happens**: Twenty saves everything in real-time — there's no separate "edit" vs "read" mode. When you create a record, it's saved immediately, triggering the "Record is created" event before you can fill in additional fields.
**سبب حدوث هذا**: تقوم Twenty بحفظ كل شيء في الزمن الحقيقي — لا يوجد وضع منفصل "edit" مقابل "read". عند إنشاء سجل، يتم حفظه فوراً، مما يؤدي إلى تشغيل حدث "Record is created" قبل أن تتمكّن من ملء حقول إضافية.
**When "Record is created" works well**:
**متى يعمل "Record is created" بشكل جيد**:
* Records created via API calls (fields are populated in a single request)
* Records created via import
* Automated record creation from other workflows
* السجلات التي تُنشأ عبر استدعاءات API (تُملأ الحقول في طلب واحد)
* السجلات التي تُنشأ عبر الاستيراد
* إنشاء السجلات تلقائياً من سير عمل أخرى
**Solution**: For records created manually in the UI, use **"Record is created or updated"** as your trigger instead. This way:
**الحل**: بالنسبة للسجلات التي تُنشأ يدوياً في واجهة المستخدم، استخدم **"Record is created or updated"** كمحفّز بدلاً من ذلك. بهذه الطريقة:
* The workflow triggers after the user has finished filling in and saving the fields
* You get the complete data rather than empty values
* سيتم تشغيل سير العمل بعد أن يُنهي المستخدم ملء الحقول وحفظها
* ستحصل على البيانات الكاملة بدلاً من القيم الفارغة
<Tip>
If you only want the workflow to run once per record, add a Filter action to check a field like `createdAt equals updatedAt` (first save) or use a custom checkbox field to track if the workflow has already run.
إذا كنت تريد تشغيل سير العمل مرة واحدة فقط لكل سجل، أضِف إجراء تصفية لفحص حقل مثل `createdAt equals updatedAt` (الحفظ الأول) أو استخدم حقلاً مخصصاً من نوع خانة اختيار لتتبع ما إذا كان سير العمل قد تم تشغيله بالفعل.
</Tip>
### Actions Failing
### فشل الإجراءات
**Symptoms**: Workflow runs but some actions fail.
**الأعراض**: يعمل سير العمل لكن بعض الإجراءات تفشل.
**Possible Causes**:
**الأسباب المحتملة**:
1. **Missing data**: Required fields are empty
2. **Invalid references**: Variables from previous steps don't exist
3. **API errors**: External services returning errors
4. **Permission issues**: Action requires permissions you don't have
1. **بيانات مفقودة**: الحقول المطلوبة فارغة
2. **مراجع غير صالحة**: المتغيّرات من الخطوات السابقة غير موجودة
3. **أخطاء API**: تعيد الخدمات الخارجية أخطاء
4. **مشكلات الأذونات**: يتطلب الإجراء أذونات لا تملكها
**حلول**:
* Check the workflow run details for error messages
* Verify all required fields have values
* Test API connections independently
* Review role permissions
* راجِع تفاصيل تشغيل سير العمل بحثاً عن رسائل الخطأ
* تحقّق من أن جميع الحقول المطلوبة تحتوي على قيم
* اختبر اتصالات API بشكل مستقل
* راجِع أذونات الدور
### HTTP Request Errors
### أخطاء طلبات HTTP
**Symptoms**: HTTP Request actions fail or return unexpected results.
**الأعراض**: تفشل إجراءات طلب HTTP أو تُرجِع نتائج غير متوقعة.
**Common Error Codes**:
**رموز الأخطاء الشائعة**:
* **400**: Bad request - check your request body format
* **401**: Unauthorized - verify API key
* **403**: Forbidden - check API permissions
* **404**: Not found - verify endpoint URL
* **429**: Too many requests - implement rate limiting
* **500**: Server error - external service issue
* **400**: طلب غير صالح - تحقّق من تنسيق جسم الطلب
* **401**: غير مُخوَّل - تحقّق من مفتاح API
* **403**: محظور - تحقّق من أذونات API
* **404**: غير موجود - تحقّق من عنوان URL لنقطة النهاية
* **429**: عدد كبير جداً من الطلبات - نفّذ تحديداً لمعدل الطلبات
* **500**: خطأ في الخادم - مشكلة في خدمة خارجية
**حلول**:
* Verify API endpoint URL
* Check authentication headers
* Test the API call outside of Twenty first
* Add error handling in Code actions
* تحقّق من عنوان URL لنقطة نهاية API
* تحقّق من ترويسات المصادقة
* اختبر استدعاء API خارج Twenty أولاً
* أضِف معالجة للأخطاء في إجراءات الكود
### Code Action Errors
### أخطاء إجراءات الكود
**Symptoms**: JavaScript code fails to execute.
**الأعراض**: يفشل كود JavaScript في التنفيذ.
**Common Issues**:
**المشكلات الشائعة**:
1. **Syntax errors**: Typos or invalid JavaScript
2. **Undefined variables**: Referencing variables that don't exist
3. **Type errors**: Operations on wrong data types
4. **Timeouts**: Code taking too long to execute
1. **أخطاء الصياغة**: أخطاء إملائية أو JavaScript غير صالح
2. **متغيّرات غير معرّفة**: الإشارة إلى متغيّرات غير موجودة
3. **أخطاء النوع**: إجراء عمليات على أنواع بيانات خاطئة
4. **انتهاء المهلة**: يستغرق الكود وقتاً طويلاً للتنفيذ
**حلول**:
* Use the built-in code editor validation
* Test code logic in a JavaScript console first
* Add console.log statements for debugging
* Simplify complex operations
* استخدم التحقق المدمج في محرر الكود
* اختبر منطق الكود في وحدة تحكم JavaScript أولاً
* أضِف عبارات console.log لأغراض تصحيح الأخطاء
* بسّط العمليات المعقّدة
### Email Not Sending
### البريد الإلكتروني لا يُرسَل
**Symptoms**: Send Email action doesn't deliver emails.
**الأعراض**: لا يقوم إجراء إرسال البريد الإلكتروني بتسليم الرسائل.
**Possible Causes**:
**الأسباب المحتملة**:
1. **No email account connected**: Check Settings → Accounts
2. **Invalid email address**: Recipient email is malformed
3. **Sending limits**: Email provider rate limits reached
4. **Spam filters**: Emails being blocked
1. **لا يوجد حساب بريد إلكتروني متصل**: تحقّق من الإعدادات → الحسابات
2. **عنوان بريد إلكتروني غير صالح**: عنوان بريد المستلم غير صحيح التنسيق
3. **قيود الإرسال**: تم الوصول إلى حدود معدل مزوّد البريد الإلكتروني
4. **مرشّحات البريد العشوائي**: يتم حظر الرسائل
**حلول**:
* Verify email account connection
* Validate recipient email addresses
* Check email provider limits
* Review email content for spam triggers
* تحقّق من اتصال حساب البريد الإلكتروني
* تحقّق من صحة عناوين بريد المستلمين
* تحقّق من حدود مزوّد البريد الإلكتروني
* راجِع محتوى البريد بحثاً عن عناصر قد تُحفِّز مرشّحات البريد العشوائي
## Debugging Workflows
## تصحيح أخطاء سير العمل
### Using Workflow Runs
### استخدام عمليات تشغيل سير العمل
1. Go to the workflow editor
2. Open the **Runs** panel
3. Find the failed run
4. Click to see step-by-step details
5. Review error messages and output data
1. انتقل إلى محرر سير العمل
2. افتح لوحة **Runs**
3. اعثر على عملية التشغيل التي فشلت
4. انقر لعرض التفاصيل خطوة بخطوة
5. راجِع رسائل الخطأ وبيانات المخرجات
### Testing Individual Steps
### اختبار الخطوات بشكل فردي
1. For Code actions, use the **Test** button
2. For HTTP requests, test the endpoint separately
3. Create test records to trigger workflows
4. Use manual triggers for controlled testing
1. بالنسبة لإجراءات الكود، استخدم زر **Test**
2. بالنسبة لطلبات HTTP، اختبر نقطة النهاية بشكل منفصل
3. أنشئ سجلات اختبار لتشغيل سير العمل
4. استخدم المُحفِّزات اليدوية للاختبار المُتحكَّم فيه
### Common Debugging Patterns
### أنماط شائعة لتصحيح الأخطاء
**Add logging**:
Use Code actions to log intermediate values for debugging.
**أضِف التسجيل**:
استخدم إجراءات الكود لتسجيل القيم الوسيطة لأغراض تصحيح الأخطاء.
**Isolate steps**:
Test each step independently to identify failures.
**اعزل الخطوات**:
اختبر كل خطوة بشكل مستقل لتحديد مواضع الفشل.
**Check data flow**:
Verify that each step receives the expected input data.
**تحقّق من تدفق البيانات**:
تأكّد من أن كل خطوة تتلقى بيانات الإدخال المتوقعة.
## Best Practices to Avoid Issues
## أفضل الممارسات لتجنّب المشكلات
### Before Activation
### قبل التفعيل
* Test thoroughly in draft mode
* Validate all API connections
* Review trigger conditions carefully
* Document expected behavior
* اختبر بدقة في وضع المسودة
* تحقّق من صحة جميع اتصالات API
* راجِع شروط المُحفِّز بعناية
* وثّق السلوك المتوقع
### During Development
### أثناء التطوير
* Use descriptive step names
* Add comments in Code actions
* Test with realistic data
* Plan for edge cases
* استخدم أسماء خطوات وصفية
* أضِف تعليقات في إجراءات الكود
* اختبر ببيانات واقعية
* خطّط للحالات الحدّية
### After Activation
### بعد التفعيل
* Monitor initial runs closely
* Set up alerts for failures
* Review run history regularly
* Keep workflows simple when possible
* راقِب عمليات التشغيل الأولى عن كثب
* قم بإعداد تنبيهات لحالات الفشل
* راجِع سجلّ التشغيل بانتظام
* اجعل سير العمل بسيطًا قدر الإمكان
@@ -47,6 +47,16 @@ V závislosti na nastavení vaší schránky, můžete vidět:
## Chování synchronizace emailu
### Sync Rate
Twenty imports emails at approximately **400 messages per minute**. This rate is currently limited by Gmail API rate limiting (and applies similarly to other providers).
For reference:
* 1,000 emails → ~2.5 minutes
* 10,000 emails → ~25 minutes
* 50,000 emails → ~2 hours
### Co se synchronizuje
* **Externí emaily**: Všechny emaily s kontakty mimo vaši organizaci
@@ -60,12 +70,12 @@ V závislosti na nastavení vaší schránky, můžete vidět:
* **Skupinové emaily**: Distribuční seznamy a skupinové emailové zprávy jsou vyloučeny
* **Vyloučené složky**: Složky, které jste se rozhodli nesynchronizovat (nastavení pod Nastavení → Účty → Email)
### Selektivní synchronizace složek (Laboratorní funkce)
### Selective Folder Sync
Ovládejte, které emailové složky se synchronizují s Twenty:
1. Povolte `Složka zpráv` v Nastavení → Načítání → Lab
2. Konfigurujte složky pod Nastavení → Účty → Email
1. Go to **Settings → Accounts** and select your connected email account
2. Configure folders under the Email section
3. Vyberte konkrétní složky k zahrnutí nebo vyloučení (příchozí, odeslané, archiv, vlastní složky)
## Řešení problémů s synchronizací emailu
@@ -25,7 +25,7 @@ Každá připojená schránka má vlastní nastavení:
* **Viditelnost e-mailů**: Zvolte, co mohou vidět členové týmu
* **Automatické vytváření kontaktů**: Povolit/zakázat pro jednotlivé schránky
* **Výběr složek**: Zvolte, které složky synchronizovat (experimentální funkce)
* **Folder selection**: Choose which folders to sync
## Jak se e-maily zobrazují
@@ -7,12 +7,12 @@ description: Troubleshooting missing emails on records.
### 1. Initial Sync Still in Progress
Email sync takes time, especially for large mailboxes.
Email sync takes time, especially for large mailboxes. Twenty imports emails at approximately **400 messages per minute** (limited by Gmail API rate limiting).
* **Calendar sync**: Completes in minutes
* **Email sync**: Can take several hours for large mailboxes
* **Email sync**: Depends on mailbox size (e.g., 10,000 emails ≈ 25 minutes, 50,000 emails ≈ 2 hours)
**Solution**: Wait up to a few hours for the initial import to complete.
**Solution**: Wait for the initial import to complete. You can estimate timing based on your mailbox size.
### 2. Contact Doesn't Exist in Twenty
@@ -11,11 +11,9 @@ Ve výchozím nastavení Twenty synchronizuje všechny externí emaily z vaší
Ovládejte, které emailové složky se synchronizují s Twenty:
1. Přejděte do **Nastavení → Vydání → Lab**
2. Povolte **Složku zpráv**
3. Vraťte se na **Nastavení → Účty**
4. Vyberte svůj připojený emailový účet
5. Vyberte, které složky chcete synchronizovat:
1. Přejděte na **Nastavení → Účty**
2. Vyberte svůj připojený emailový účet
3. Vyberte, které složky chcete synchronizovat:
| Složka | Popis |
| ------------------ | --------------------------------------- |
@@ -34,11 +34,10 @@ image: /images/user-guide/emails/emails_header.png
Pro další poskytovatele emailu a kalendáře:
1. Přejděte na **Nastavení → Vydání → Laboratoř** pro povolení funkce
2. Vraťte se na **Nastavení → Účty**
3. Nakonfigurujte nastavení SMTP pro email
4. Nakonfigurujte nastavení CalDAV pro kalendář
5. Otestujte připojení
1. Přejděte na **Nastavení → Účty**
2. Nakonfigurujte nastavení SMTP pro email
3. Nakonfigurujte nastavení CalDAV pro kalendář
4. Otestujte připojení
### Více Poštovních Schránek
@@ -69,13 +68,12 @@ Vyberte různé úrovně viditelnosti pro vaše emaily:
<Note>When enabled, contacts are automatically linked to their Company records based on their email domain. If the company doesn't exist yet, Twenty creates it for you.</Note>
### Řízení, které emaily se synchronizují s Výběrem Složek Zpráv (Laboratorní Funkce)
### Control which emails get synced with Message Folder Selection
Ovládejte, které emailové složky se synchronizují s Twenty:
1. Přejděte na **Nastavení → Vydání → Laboratoř** a povolte **Složku Zpráv**
2. Vraťte se na **Nastavení → Účty** a vyberte svůj propojený emailový účet
3. Vyberte, které složky chcete synchronizovat:
1. Go to **Settings → Accounts** and select your connected email account
2. Vyberte, které složky chcete synchronizovat:
* **Doručená Pošta**: Hlavní příchozí emaily
* **Odeslané**: Odchozí emaily, které jste odeslali
* **Vlastní Složky**: Jakékoli specifické složky, které chcete zahrnout
@@ -123,7 +121,7 @@ Vyberte, co bude viditelné pro ostatní uživatele ve vašem pracovním prostor
**Aktualizace každých 5 minut**: Data emailu a kalendáře se automaticky synchronizují každých 5 minut po úvodním importu.
<Note>
**Initial sync timing**: Calendar sync completes quickly (usually within minutes), while email sync takes longer for large mailboxes—up to a few hours depending on volume. Don't worry if you see contacts from calendar events appearing before your email contacts; this is normal behavior.
**Initial sync timing**: Calendar sync completes quickly (usually within minutes), while email sync takes longer for large mailboxes. Twenty imports emails at approximately **400 messages per minute** (limited by Gmail API rate limiting), so a mailbox with 10,000 emails takes about 25 minutes. Don't worry if you see contacts from calendar events appearing before your email contacts; this is normal behavior.
</Note>
## Další kroky
@@ -8,6 +8,10 @@ image: /images/user-guide/reporting/pie-chart.png
<img src="/images/user-guide/reporting/pie-chart.png" alt="Panely" />
</Frame>
<Note>
Dashboards are currently in beta. Activate them under **Settings → Updates → Early Access**.
</Note>
## Porozumění řídicím panelům
Řídicí panely v Twenty poskytují vizuální způsob, jak sledovat klíčové výkonnostní metriky a získávat přehledy z dat vašeho CRM.
@@ -1,122 +1,122 @@
---
title: Fix Import Errors
description: Complete troubleshooting guide for resolving CSV import errors.
title: Oprava chyb importu
description: Kompletní průvodce odstraňováním chyb při importu CSV.
---
## Přehled
Import not working? This guide helps you identify and fix common import errors step by step.
Nefunguje import? Tato příručka vám krok za krokem pomůže identifikovat a opravit běžné chyby při importu.
## How Import Validation Works
## Jak funguje validace importu
After uploading your file and mapping columns, Twenty validates your data:
Po nahrání souboru a namapování sloupců Twenty vaše data ověří:
1. **Validation runs** — Twenty checks each row for errors
2. **Errors are highlighted** — problematic rows appear in **yellow**
3. **You can fix in-place** — edit cells directly in the import UI
4. **Or remove rows** — skip problematic records entirely
1. **Proběhne validace** — Twenty zkontroluje každý řádek na chyby
2. **Chyby jsou zvýrazněny** — problematické řádky se zobrazí **žlutě**
3. **Můžete opravovat přímo na místě** — upravujte buňky přímo v rozhraní importu
4. **Nebo odstraňte řádky** — problematické záznamy úplně přeskočte
<Note>**Fix errors in the UI.** You don't need to go back to your spreadsheet. Edit cells directly during import to save time.</Note>
<Note>**Opravujte chyby v rozhraní.** Nemusíte se vracet do své tabulky. Úpravou buněk přímo během importu ušetříte čas.</Note>
## Step-by-Step Troubleshooting
## Řešení problémů krok za krokem
### Step 1: Identify the Error Type
### Krok 1: Určete typ chyby
Click on a highlighted row to see the specific error message. Common error types:
Klikněte na zvýrazněný řádek a zobrazí se konkrétní chybová zpráva. Běžné typy chyb:
| Chybová zpráva | What It Means |
| --------------------------------------------------------------------- | ------------------------------------------------------------ |
| Duplicate values highlighted in yellow | Value already exists in Twenty or appears twice in your file |
| `{field} is not a valid {type}` (hover on yellow cell) | Data doesn't match expected format |
| Required field highlighted | A required field is empty |
| `Can't connect to {object}. No unique record found...` (import fails) | Referenced record doesn't exist |
| `Too many records. Up to 10000 allowed` (upload blocked) | File has more than 10,000 records |
| Chybová zpráva | Co to znamená |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| Duplicitní hodnoty zvýrazněné žlutě | Hodnota již existuje v Twenty nebo se ve vašem souboru vyskytuje dvakrát |
| `{field} is not a valid {type}` (přejeďte myší na žlutou buňku) | Data neodpovídají očekávanému formátu |
| Povinné pole je zvýrazněno | Povinné pole je prázdné |
| `Can't connect to {object}. No unique record found...` (import selže) | Odkazovaný záznam neexistuje |
| `Too many records. Up to 10000 allowed` (nahrávání zablokováno) | Soubor obsahuje více než 10 000 záznamů |
### Step 2: Fix the Error
### Krok 2: Opravte chybu
Follow the specific instructions below for each error type.
Postupujte podle níže uvedených pokynů pro jednotlivé typy chyb.
---
## Error: Duplicate Value
## Chyba: Duplicitní hodnota
### Co uvidíte
Rows with duplicate values are **highlighted in yellow** in the import UI before the import starts.
Řádky s duplicitními hodnotami jsou v rozhraní importu před zahájením importu **zvýrazněny žlutě**.
### What It Means
### Co to znamená
A unique field (email, domain) either:
Jedinečné pole (e-mail, doména):
* Already exists in Twenty
* Appears twice in your file
* Již existuje v Twenty
* Se ve vašem souboru vyskytuje dvakrát
### How to Fix
### Jak to opravit
**Option 1: Edit the duplicate value**
**Možnost 1: Upravit duplicitní hodnotu**
1. Click the cell with the error
2. Change to a unique value
3. Continue with import
1. Klikněte na buňku s chybou
2. Změňte na jedinečnou hodnotu
3. Pokračujte v importu
**Option 2: Remove the duplicate row**
**Možnost 2: Odstranit duplicitní řádek**
1. Click the X next to the row
2. The row will be skipped during import
1. Klikněte na X vedle řádku
2. Řádek bude během importu přeskočen
**Option 3: Let Twenty update the existing record**
**Možnost 3: Nechte Twenty aktualizovat existující záznam**
1. Ensure your file includes a unique identifier (`email`, `domain`, or `id`)
2. Map the unique identifier field
3. Twenty will update the existing record instead of creating a duplicate
1. Ujistěte se, že váš soubor obsahuje jedinečný identifikátor (`email`, `domain` nebo `id`)
2. Namapujte pole jedinečného identifikátoru
3. Twenty aktualizuje existující záznam místo vytvoření duplicity
<Note>
**You can update unique fields too.**
**Můžete aktualizovat i jedinečná pole.**
* If you keep the `id` but change the `email` → the email will be updated
* If you keep the `email` but change the `id` → the id will be updated
* Pokud ponecháte `id`, ale změníte `email` → e-mail bude aktualizován
* Pokud ponecháte `email`, ale změníte `id` → ID bude aktualizováno
As long as one unique identifier matches, Twenty updates the record.
Pokud se shoduje alespoň jeden jedinečný identifikátor, Twenty záznam aktualizuje.
</Note>
### How to Prevent This Error
### Jak této chybě předejít
Before importing:
Před importem:
1. Sort your spreadsheet by the unique field
2. Remove duplicate rows
3. Check if records already exist in Twenty
1. Seřaďte svou tabulku podle jedinečného pole
2. Odstraňte duplicitní řádky
3. Zkontrolujte, zda záznamy v Twenty již existují
<Warning>
**Soft-deleted records count toward uniqueness.**
**Záznamy „soft-deleted“ se započítávají do jedinečnosti.**
Check Command Menu → See deleted records. Records there still enforce uniqueness. Permanently delete them or restore and update.
Zkontrolujte Command Menu → Zobrazit smazané záznamy. Záznamy tam stále vynucují jedinečnost. Natrvalo je smažte nebo je obnovte a aktualizujte.
</Warning>
For more details: [Uniqueness Constraints](/l/cs/user-guide/data-migration/capabilities/uniqueness-constraints)
Více podrobností: [Omezení jedinečnosti](/l/cs/user-guide/data-migration/capabilities/uniqueness-constraints)
---
## Error: Invalid Format
## Chyba: Neplatný formát
### Co uvidíte
The cell value is highlighted in yellow. Hover over it to see the error message:
Hodnota buňky je zvýrazněna žlutě. Najetím myší zobrazíte chybovou zprávu:
```
{field name} is not a valid {field type}
```
### What It Means
### Co to znamená
The data doesn't match the expected format for that field type.
Data neodpovídají očekávanému formátu pro tento typ pole.
### How to Fix — By Field Type
### Jak to opravit — podle typu pole
#### Email
**Problem:** Invalid email format
**Solution:** Use format `name@domain.com`
**Problém:** Neplatný formát e-mailu
**Řešení:** Použijte formát `name@domain.com`
```
❌ john.smith@
@@ -126,8 +126,8 @@ The data doesn't match the expected format for that field type.
#### Doména
**Problem:** Inconsistent format may cause duplicates
**Solution:** Use `https://domain.com` format (recommended)
**Problém:** Nekonzistent formát může způsobit duplicity
**Řešení:** Použijte formát `https://domain.com` (doporučeno)
```
⚠️ acme.com (valid, but not recommended)
@@ -135,12 +135,12 @@ The data doesn't match the expected format for that field type.
✅ https://acme.com (recommended)
```
<Note>All formats are valid, but `https://domain.com` is recommended because it matches the format used by email/calendar sync. Using other formats may create duplicate companies.</Note>
<Note>Všechny formáty jsou platné, ale `https://domain.com` je doporučený, protože odpovídá formátu používanému synchronizací e-mailu/kalendáře. Použití jiných formátů může vytvářet duplicitní společnosti.</Note>
#### Datum
**Problem:** Unrecognized date format
**Solution:** Use consistent format throughout file
**Problém:** Nerozpoznaný formát data
**Řešení:** Používejte jednotný formát v celém souboru
```
✓ 2024-03-15 (YYYY-MM-DD - recommended)
@@ -150,10 +150,10 @@ The data doesn't match the expected format for that field type.
#### Telefon
**Problem:** Missing required columns
**Solution:** Include all phone columns
**Problém:** Chybí požadované sloupce
**Řešení:** Zahrňte všechny telefonní sloupce
| Column | Příklad |
| Sloupec | Příklad |
| --------------------------------------- | ------------ |
| **Phones / Primary Phone Number** | `4159095555` |
| **Phones / Primary Phone Country Code** | `US` |
@@ -161,8 +161,8 @@ The data doesn't match the expected format for that field type.
#### Booleovská hodnota
**Problem:** Wrong boolean value
**Solution:** Use uppercase `TRUE` or `FALSE`
**Problém:** Nesprávná booleovská hodnota
**Řešení:** Použijte velká písmena `TRUE` nebo `FALSE`
```
❌ true
@@ -172,17 +172,17 @@ The data doesn't match the expected format for that field type.
✓ FALSE
```
#### Select / Multi-Select
#### Výběr / Vícevýběr
**Problem:** Value doesn't match existing options
**Solution:** Use **API names**, not display labels
**Problém:** Hodnota neodpovídá existujícím možnostem
**Řešení:** Používejte **názvy API**, ne zobrazované štítky
How to find API names:
Jak najít názvy API:
1. Go to **Settings → Data Model**
2. Select the object and field
3. Enable **Advanced mode** (toggle at bottom right)
4. Use the API name (e.g., `OPTION_1`, not "Option 1")
1. Přejděte na **Nastavení → Datový model**
2. Vyberte objekt a pole
3. Povolte **Pokročilý režim** (přepínač vpravo dole)
4. Použijte název API (např. `OPTION_1`, ne "Option 1")
```
❌ High Priority
@@ -191,18 +191,18 @@ How to find API names:
#### Měna
**Problem:** Missing amount or currency code
**Solution:** Fill both columns
**Problém:** Chybí částka nebo kód měny
**Řešení:** Vyplňte oba sloupce
| Column | Příklad |
| Sloupec | Příklad |
| --------------------- | --------- |
| **Amount / Amount** | `1234.56` |
| **Amount / Currency** | `USD` |
#### Číslo
**Problem:** Non-numeric characters
**Solution:** Numbers only, period for decimals
**Problém:** Nečíselné znaky
**Řešení:** Pouze čísla, tečka pro desetinná místa
```
❌ $1,234.56
@@ -210,221 +210,221 @@ How to find API names:
✓ 1234.56
```
For complete format reference: [Field Mapping](/l/cs/user-guide/data-migration/capabilities/field-mapping)
Úplná referenční příručka k formátům: [Mapování polí](/l/cs/user-guide/data-migration/capabilities/field-mapping)
---
## Error: Required Field Missing
## Chyba: Chybí povinné pole
### Co uvidíte
The row is highlighted in yellow with the required field cell marked.
Řádek je zvýrazněn žlutě a buňka povinného pole je označena.
### What It Means
### Co to znamená
A required field is empty for this row.
U tohoto řádku je povinné pole prázdné.
### How to Fix
### Jak to opravit
**Option 1: Enter a value**
**Možnost 1: Zadejte hodnotu**
1. Click the empty cell
2. Enter a value
3. Continue with import
1. Klikněte na prázdnou buňku
2. Zadejte hodnotu
3. Pokračujte v importu
**Option 2: Remove the row**
**Možnost 2: Odstraňte řádek**
1. If you don't have the data, click X to skip the row
1. Pokud data nemáte, klikněte na X a řádek přeskočte
### How to Prevent This Error
### Jak této chybě předejít
Before importing, identify required fields:
Před importem si určete povinná pole:
1. Go to **Settings → Data Model**
2. Select your object
3. Check which fields are marked as required
1. Přejděte na **Nastavení → Datový model**
2. Vyberte objekt
3. Zkontrolujte, která pole jsou označena jako povinná
---
## Error: Relation Not Found
## Chyba: Vztah nebyl nalezen
### Co uvidíte
This error appears **after the import starts** — the import fails with a message like:
Tato chyba se objeví **po zahájení importu** — import selže se zprávou jako:
```
Can't connect to company. No unique record found with condition: id = 7776ee49-f608-4a77-8cc8-6fe96ae1e43f
```
This means there is no Company in Twenty with that specific identifier.
To znamená, že v Twenty neexistuje společnost s tímto konkrétním identifikátorem.
<Note>Unlike other errors, this one is not caught during the data review step. The import will start and then fail when it encounters the missing relation.</Note>
<Note>Na rozdíl od jiných chyb tato není zachycena během kroku kontroly dat. Import se spustí a poté selže, jakmile narazí na chybějící relaci.</Note>
### What It Means
### Co to znamená
You're trying to link to a record that doesn't exist in Twenty.
Pokoušíte se propojit se záznamem, který v Twenty neexistuje.
### How to Fix
### Jak to opravit
**Option 1: Import parent records first**
**Možnost 1: Nejprve importujte nadřazené záznamy**
1. Cancel the current import
2. Import the parent records (e.g., Companies)
3. Then import the child records (e.g., People)
1. Zrušte aktuální import
2. Importujte nadřazené záznamy (např. společnosti)
3. Poté importujte podřízené záznamy (např. osoby)
**Option 2: Fix the reference value**
**Možnost 2: Opravte referenční hodnotu**
1. Check the reference value in your file
2. Ensure it exactly matches an existing record
3. Verify format: domains should be `https://domain.com`
1. Zkontrolujte referenční hodnotu ve svém souboru
2. Ujistěte se, že přesně odpovídá existujícímu záznamu
3. Ověřte formát: domény by měly být `https://domain.com`
**Option 3: Remove the relation**
**Možnost 3: Odstraňte relaci**
1. Clear the cell to import without the relation
2. Add the relation manually later
1. Vymažte buňku a importujte bez relace
2. Relaci přidejte později ručně
### How to Prevent This Error
### Jak této chybě předejít
1. **Import in the correct order:**
* Companies first
* People second (with company references)
* Opportunities third
1. **Importujte ve správném pořadí:**
* Nejprve společnosti
* Poté osoby (s odkazy na společnost)
* Nakonec příležitosti
2. **Verify reference values:**
* Export parent records to get exact identifiers
* Use domain format `https://domain.com`
* Check for typos and case sensitivity
2. **Ověřte referenční hodnoty:**
* Exportujte nadřazené záznamy, abyste získali přesné identifikátory
* Používejte formát domény `https://domain.com`
* Zkontrolujte překlepy a velikost písmen
<Warning>
**Import will fail if a reference is made to a non-existent record.**
**Import selže, pokud je odkazováno na neexistující záznam.**
Always import parent objects before child objects.
Vždy importujte nadřazené objekty před podřízenými objekty.
</Warning>
For more details: [Import Relations](/l/cs/user-guide/data-migration/capabilities/import-relations)
Více podrobností: [Import rela](/l/cs/user-guide/data-migration/capabilities/import-relations)
---
## Error: File Too Large
## Chyba: Soubor je příliš velký
### Co uvidíte
This error appears **when uploading your file** — the upload is blocked entirely:
Tato chyba se objeví **při nahrávání souboru** — nahrávání je zcela zablokováno:
```
Too many records. Up to 10000 allowed
```
You won't be able to proceed to the data review step until you reduce the file size.
Dokud nezmenšíte velikost souboru, nebudete moci pokračovat ke kroku kontroly dat.
### What It Means
### Co to znamená
Your file has more than 10,000 records.
Váš soubor má více než 10 000 záznamů.
### How to Fix
### Jak to opravit
**Option 1: Split into multiple files**
**Možnost 1: Rozdělte na více souborů**
1. Divide your data into files of 10,000 records or fewer
2. Import each file separately
3. Maintain import order (Companies before People)
1. Rozdělte data do souborů s nejvýše 10 000 záznamy
2. Importujte každý soubor zvlášť
3. Dodržte pořadí importu (společnosti před osobami)
**Option 2: Use API import**
For very large datasets, use the API which has no record limit.
See: [How to Import Data via API](/l/cs/user-guide/data-migration/how-tos/import-data-via-api)
**Možnost 2: Použijte import přes API**
U velmi velkých datových sad použijte API, které nemá limit počtu záznamů.
Viz: [Jak importovat data přes API](/l/cs/user-guide/data-migration/how-tos/import-data-via-api)
---
## Error: Field Not Recognized
## Chyba: Pole nebylo rozpoznáno
### What It Means
### Co to znamená
A column in your file can't be mapped because the field doesn't exist in Twenty.
Sloupec ve vašem souboru nelze namapovat, protože pole v Twenty neexistuje.
### How to Fix
### Jak to opravit
1. Go to **Settings → Data Model**
2. Select the object you're importing
3. Click **+ Add field**
4. Create the custom field with the appropriate type
5. Re-upload your file
1. Přejděte na **Nastavení → Datový model**
2. Vyberte objekt, který importujete
3. Klikněte na **+ Add field**
4. Vytvořte vlastní pole s odpovídajícím typem
5. Nahrajte soubor znovu
<Note>The CSV import creates records, not fields. All fields must exist before importing.</Note>
<Note>Import CSV vytváří záznamy, nikoli pole. Všechna pole musí existovat před importem.</Note>
---
## Error: User Relation Empty
## Chyba: Prázdná relace uživatele
### What It Means
### Co to znamená
You're trying to assign a record to a user (Owner, Assignee) but the relation isn't being mapped.
Pokoušíte se přiřadit záznam uživateli (Owner, Assignee), ale relace se nemapuje.
### Common Causes
### Časté příčiny
1. **User hasn't accepted their invitation** — the user doesn't exist in Twenty yet
2. **Using user ID from old system** — Twenty can't match IDs from another system
3. **Wrong email format** — the email doesn't match the user's Twenty account
1. **Uživatel nepřijal pozvánku** — uživatel zatím v Twenty neexistuje
2. **Používáte uživatelské ID ze starého systému** — Twenty nedokáže spárovat ID z jiného systému
3. **Nesprávný formát e-mailu** — e-mail neodpovídá účtu uživatele v Twenty
### How to Fix
### Jak to opravit
1. Ensure all users have **accepted their invitation** to your Twenty workspace
2. Use the user's **email address** (not their name or old system ID)
3. Use the same email they used to join Twenty
1. Ujistěte se, že všichni uživatelé **přijali svou pozvánku** do vašeho pracovního prostoru Twenty
2. Použijte **e-mailovou adresu** uživatele (ne jeho jméno nebo ID ze starého systému)
3. Použijte stejný e-mail, jaký použili k připojení do Twenty
<Warning>
**Users must accept invitations before importing.**
**Uživatelé musí před importem přijmout pozvánky.**
If a user hasn't accepted their invitation, records referencing them will have empty user relations.
Pokud uživatel nepřijal svou pozvánku, záznamy na něj odkazující budou mít prázdnou relaci uživatele.
</Warning>
---
## Pre-Import Checklist
## Kontrolní seznam před importem
Avoid errors by checking these before importing:
Vyhněte se chybám tím, že před importem zkontrolujete následující:
### File Requirements
### Požadavky na soubor
<Check>File is CSV, XLSX, or XLS format</Check>
<Check>File has fewer than 10,000 records</Check>
<Check>File uses UTF-8 encoding</Check>
<Check>Soubor je ve formátu CSV, XLSX nebo XLS</Check>
<Check>Soubor obsahuje méně než 10 000 záznamů</Check>
<Check>Soubor používá kódování UTF-8</Check>
### Data Quality
### Kvalita dat
<Check>No duplicate emails (for People)</Check>
<Check>No duplicate domains (for Companies)</Check>
<Check>All dates use consistent format</Check>
<Check>All domains use `https://domain.com` format</Check>
<Check>Žádné duplicitní e-maily (pro osoby)</Check>
<Check>Žádné duplicitní domény (pro společnosti)</Check>
<Check>Všechny datumy používají jednotný formát</Check>
<Check>Všechny domény používají formát `https://domain.com`</Check>
### Field Formats
### Formáty polí
<Check>Boolean fields use `TRUE` or `FALSE` (uppercase)</Check>
<Check>Select fields use API names, not display labels</Check>
<Check>Phone fields have all required columns</Check>
<Check>Currency fields have both Amount and Currency Code</Check>
<Check>Logická pole používají `TRUE` nebo `FALSE` (velkými písmeny)</Check>
<Check>Pole typu výběr používají názvy API, ne zobrazované štítky</Check>
<Check>Telefonní pole mají všechny požadované sloupce</Check>
<Check>Měnová pole obsahují částku i kód měny</Check>
### Vztahy
<Check>Parent records imported before child records</Check>
<Check>Relation columns reference existing records</Check>
<Check>Domain format matches Twenty's format exactly</Check>
<Check>Nadřazené záznamy importovány před podřízenými záznamy</Check>
<Check>Sloupce relací odkazují na existující záznamy</Check>
<Check>Formát domény přesně odpovídá formátu Twenty</Check>
### Datový model
<Check>All custom fields exist in Settings → Data Model</Check>
<Check>Select options exist before importing</Check>
<Check>Všechna vlastní pole existují v Nastavení → Datový model</Check>
<Check>Možnosti výběru existují před importem</Check>
---
## Still Having Issues?
## Stále máte potíže?
If you've tried the above solutions:
Pokud jste vyzkoušeli výše uvedená řešení:
1. **Download the sample file** — see the exact format Twenty expects
2. **Export existing records** — compare your file to working data
3. **Test with a small batch** — try 5-10 rows first
4. **Check the reference articles:**
* [Field Mapping](/l/cs/user-guide/data-migration/capabilities/field-mapping)
* [Uniqueness Constraints](/l/cs/user-guide/data-migration/capabilities/uniqueness-constraints)
* [Import Relations](/l/cs/user-guide/data-migration/capabilities/import-relations)
* [Error Handling](/l/cs/user-guide/data-migration/capabilities/error-handling)
1. **Stáhněte si ukázkový soubor** — uvidíte přesný formát, který Twenty očekává
2. **Exportujte existující záznamy** — porovnejte svůj soubor s funkčními daty
3. **Otestujte s malou dávkou** — nejprve zkuste 510 řádků
4. **Zkontrolujte referenční články:**
* [Mapování polí](/l/cs/user-guide/data-migration/capabilities/field-mapping)
* [Omezení jedinečnosti](/l/cs/user-guide/data-migration/capabilities/uniqueness-constraints)
* [Import rela](/l/cs/user-guide/data-migration/capabilities/import-relations)
* [Zpracování chyb](/l/cs/user-guide/data-migration/capabilities/error-handling)
@@ -1,103 +1,103 @@
---
title: Import Relations Between Objects via CSV
description: Complete step-by-step guide to linking records during CSV import.
title: Import relací mezi objekty pomocí CSV
description: Kompletní podrobný průvodce propojením záznamů během importu CSV.
---
## Přehled
This guide walks you through importing relations between objects—for example, linking People to Companies, or Opportunities to People.
Tento průvodce vás provede importem relací mezi objekty — například propojením lidí se společnostmi nebo příležitostí s lidmi.
<Note>**What can be imported:** Only one-to-many relations pointing to a single object type. Relations pointing to multiple object types (like Notes linking to People AND Companies) are not yet supported for import.</Note>
<Note>**Co lze importovat:** Pouze relace „jeden ku mnoha“ směřující k jednomu typu objektu. Relace směřující k více typům objektů (např. poznámky propojené s lidmi a společnostmi) zatím nejsou pro import podporovány.</Note>
## Understanding Relations
## Porozumění relacím
### What is a "One-to-Many" Relation?
### Co je to relace „jeden ku mnoha“?
In a one-to-many relation:
V relaci jeden ku mnoha:
* **One** Company has **many** People (employees)
* **One** Company has **many** Opportunities
* **One** Person has **many** Tasks
* **Jedna** společnost má **mnoho** lidí (zaměstnanců)
* **Jedna** společnost má **mnoho** příležitostí
* **Jedna** osoba má **mnoho** úkolů
The "one" side is the **parent**. The "many" side is the **child**.
Strana „jedna“ je **nadřazená**. Strana „mnoho“ je **podřízená**.
### Common Relations in Twenty
### Běžné relace v Twenty
| Vztah | "One" Side (Parent) | "Many" Side (Child) |
| ------------------------- | ------------------- | ------------------- |
| Companies → People | Společnost | Osoby |
| Companies → Opportunities | Společnost | Příležitosti |
| People → Tasks | Osoba | Úkoly |
| People → Notes | Osoba | Poznámky |
| Vztah | Strana „jedna“ (nadřazený) | Strana „mnoho“ (podřízený) |
| -------------------------- | -------------------------- | -------------------------- |
| Společnosti → Lidé | Společnost | Osoby |
| Společnosti → Příležitosti | Společnost | Příležitosti |
| Lidé → Úkoly | Osoba | Úkoly |
| Lidé → Poznámky | Osoba | Poznámky |
## Step 1: Identify the "One" and "Many" Sides
## Krok 1: Určete strany „jedna“ a „mnoho“
Before importing, determine which object is the parent and which is the child.
Před importem určete, který objekt je nadřazený a který podřízený.
**Ask yourself:** "Does ONE [Object A] have MANY [Object B]?"
**Zeptejte se sami sebe:** "Má JEDEN [Objekt A] MNOHO [Objekt B]?"
* One Company → Many People ✓ (Company is parent)
* One Person → Many Companies ✗ (This is wrong—a person belongs to one company)
* Jedna společnost → Mnoho lidí ✓ (společnost je nadřazená)
* Jedna osoba → Mnoho společností ✗ (To je špatně — osoba patří k jedné společnosti)
## Step 2: Import the Parent Records First
## Krok 2: Nejprve importujte nadřazené záznamy
The parent ("one" side) must exist in Twenty before you can reference it.
Nadřazený („jedna“ strana) musí v Twenty existovat, než na něj budete moci odkazovat.
**Import order:**
**Pořadí importu:**
1. **Companies** first (no dependencies)
2. **People** second (link to Companies)
3. **Opportunities** third (link to Companies and/or People)
4. **Tasks/Notes** (link to any of the above)
1. **Společnosti** jako první (bez závislostí)
2. **Lidé** jako druzí (propojení se společnostmi)
3. **Příležitosti** jako třetí (propojené se společnostmi a/nebo lidmi)
4. **Úkoly/Poznámky** (propojené s jakýmkoli z výše uvedených)
<Warning>
**If the parent record doesn't exist, the import will fail.**
**Pokud nadřazený záznam neexistuje, import selže.**
Always verify that Companies are imported before importing People with company references.
Vždy ověřte, že společnosti jsou importovány dříve, než budete importovat lidi s odkazy na společnost.
</Warning>
## Step 3: Note the Parent's Unique Identifier
## Krok 3: Poznamenejte si jedinečný identifikátor nadřazeného objektu
You need to reference the parent record using a **unique identifier**. Available options:
Na nadřazený záznam musíte odkazovat pomocí **jedinečného identifikátoru**. Dostupné možnosti:
| Parent Object | Available Unique Identifiers |
| ------------------------------- | --------------------------------------------------------------- |
| **Společnosti** | `id` (UUID), `domain` (recommended), or any custom unique field |
| **People** | `id` (UUID), `email`, or any custom unique field |
| **Členové pracovního prostoru** | `id` (UUID), `email` (not name) |
| **Vlastní objekty** | `id` (UUID), or any field marked as unique |
| Nadřazený objekt | Dostupné jedinečné identifikátory |
| ------------------------------- | ----------------------------------------------------------------------- |
| **Společnosti** | `id` (UUID), `domain` (doporučeno) nebo jakékoli vlastní jedinečné pole |
| **Lidé** | `id` (UUID), `email` nebo jakékoli vlastní jedinečné pole |
| **Členové pracovního prostoru** | `id` (UUID), `email` (ne jméno) |
| **Vlastní objekty** | `id` (UUID) nebo jakékoli pole označené jako jedinečné |
<Note>**Recommended:** Use `domain` for Companies and `email` for People. These are human-readable and easy to verify in your spreadsheet.</Note>
<Note>**Doporučeno:** Pro společnosti použijte `domain` a pro lidi `email`. Jsou čitelné pro člověka a snadno ověřitelné ve vaší tabulce.</Note>
### Finding the Identifier
### Jak zjistit identifikátor
If you need the `id`:
Pokud potřebujete `id`:
1. Export the parent records from Twenty
2. The export includes the `id` column
3. Use these IDs in your child records file
1. Exportujte nadřazené záznamy z Twenty
2. Export obsahuje sloupec `id`
3. Použijte tato ID v souboru s podřízenými záznamy
## Step 4: Verify the Relation Field Exists
## Krok 4: Ověřte, že existuje relační pole
Before importing, ensure the relation field exists between your objects.
Před importem se ujistěte, že mezi vašimi objekty existuje relační pole.
**To check or create:**
**Jak ověřit nebo vytvořit:**
1. Go to **Settings → Data Model**
2. Select your child object (e.g., People)
3. Look for a relation field pointing to the parent (e.g., Company)
4. If it doesn't exist, create it:
* Click **+ Add field**
* Select **Relation** type
* Choose the parent object
1. Přejděte na **Nastavení → Datový model**
2. Vyberte svůj podřízený objekt (např. Lidé)
3. Vyhledejte relační pole směřující na nadřazený objekt (např. Společnost)
4. Pokud neexistuje, vytvořte jej:
* Klikněte na **+ Add field**
* Vyberte typ **Relation**
* Vyberte nadřazený objekt
## Step 5: Prepare Your CSV File
## Krok 5: Připravte svůj soubor CSV
Add a column to your child CSV that references the parent using its unique identifier.
Do podřízeného CSV přidejte sloupec, který odkazuje na nadřazený objekt pomocí jeho jedinečného identifikátoru.
### Example: People Linking to Companies
### Příklad: Propojení lidí se společnostmi
**Your People CSV:**
**Vaše CSV s lidmi:**
```csv
firstName,lastName,email,jobTitle,companyDomain
@@ -106,66 +106,66 @@ Jane,Doe,jane@widgets.co,CTO,https://widgets.co
Bob,Johnson,bob@techstart.io,Developer,https://techstart.io
```
The `companyDomain` column references the Company's domain.
Sloupec `companyDomain` odkazuje na doménu společnosti.
### Format Requirements
### Požadavky na formát
| Identifikátor | Formát | Příklad |
| ------------- | -------------- | -------------------------------------- |
| Doména | URL format | `https://acme.com` |
| Email | Standard email | `john@acme.com` |
| ID | UUID | `c776ee49-f608-4a77-8cc8-6fe96ae1e43f` |
| Identifikátor | Formát | Příklad |
| ------------- | ----------------- | -------------------------------------- |
| Doména | Formát URL | `https://acme.com` |
| Email | Standard e-mail | `john@acme.com` |
| ID | UUID | `c776ee49-f608-4a77-8cc8-6fe96ae1e43f` |
<Warning>
**Domain format matters!**
**Na formátu domény záleží!**
Use `https://domain.com` (not just `domain.com`). This matches how Twenty stores Company domains and prevents matching errors.
Použijte `https://domain.com` (ne pouze `domain.com`). To odpovídá způsobu, jak Twenty ukládá domény společností, a předchází chybám při párování.
</Warning>
### Important Rules
### Důležitá pravidla
1. **Exact match required** — the value must exactly match the parent record
2. **Map only ONE unique identifier** — don't include both `companyId` AND `companyDomain`
3. **Case sensitive** — `Acme.com` ≠ `acme.com`
1. **Je vyžadována přesná shoda** — hodnota se musí přesně shodovat s nadřazeným záznamem
2. **Mapujte pouze JEDEN jedinečný identifikátor** — nezahrnujte současně `companyId` A `companyDomain`
3. **Rozlišuje se velikost písmen** — `Acme.com` ≠ `acme.com`
## Step 6: Upload and Map the Relation
## Krok 6: Nahrajte a namapujte relaci
1. Navigate to the child object (e.g., People)
2. Click **⋮** → **Import records**
3. Upload your CSV file
4. In the field mapping step:
* Find your relation column (e.g., `companyDomain`)
* Map it to the **Company** relation field
5. Complete the remaining mapping
6. Review errors and confirm
1. Přejděte k podřízenému objektu (např. Lidé)
2. Klikněte na **⋮** → **Import records**
3. Nahrajte svůj soubor CSV
4. V kroku mapování polí:
* Najděte svůj relační sloupec (např. `companyDomain`)
* Namapujte jej na relační pole **Společnost**
5. Dokončete zbývající mapování
6. Zkontrolujte chyby a potvrďte
Twenty will automatically link each child record to the matching parent.
Twenty automaticky propojí každý podřízený záznam s odpovídajícím nadřazeným.
## Step 7: Verify the Import
## Krok 7: Ověřte import
After importing:
Po importu:
1. Open a few child records (e.g., People)
2. Verify the relation field shows the correct parent (e.g., Company)
3. Open a parent record and check the related records section
1. Otevřete několik podřízených záznamů (např. Lidé)
2. Ověřte, že relační pole zobrazuje správný nadřazený objekt (např. Společnost)
3. Otevřete nadřazený záznam a zkontrolujte sekci souvisejících záznamů
## Common Mistakes to Avoid
## Časté chyby, kterým se vyhnout
| Mistake | Problem | Solution |
| -------------------------- | -------------------------------------------------- | ------------------------------------------------------- |
| **Wrong import order** | Importing People before Companies | Always import parents first, then children |
| **Wrong domain format** | Using `acme.com` instead of `https://acme.com` | Use full URL format with `https://` |
| **Multiple unique fields** | Mapping both `companyId` AND `companyDomain` | Map only ONE unique identifier |
| **Missing relation field** | The relation field doesn't exist in the data model | Create it in **Settings → Data Model** before importing |
| **Non-existent records** | The parent record doesn't exist in Twenty | Import parent records first, or check for typos |
| **Case mismatch** | `Acme.com` in file but `acme.com` in Twenty | Ensure exact case matching |
| Chyba | Problém | Řešení |
| ---------------------------- | ----------------------------------------------- | --------------------------------------------------------------- |
| **Chybné pořadí importu** | Importujete lidi před společnostmi | Vždy nejprve importujte nadřazené, poté podřízené |
| **Chybný formát domény** | Použití `acme.com` místo `https://acme.com` | Použijte plný formát URL s `https://` |
| **Více jedinečných polí** | Mapujete současně `companyId` A `companyDomain` | Mapujte pouze JEDEN jedinečný identifikátor |
| **Chybí relační pole** | Relační pole v datovém modelu neexistuje | Vytvořte jej v **Nastavení → Datový model** před importem |
| **Neexistující záznamy** | Nadřazený záznam v Twenty neexistuje | Nejprve importujte nadřazené záznamy nebo zkontrolujte překlepy |
| **Rozdílná velikost písmen** | `Acme.com` v souboru, ale v Twenty `acme.com` | Zajistěte přesnou shodu velikosti písmen |
## Linking to Workspace Members
## Propojování s členy pracovního prostoru
When linking to Workspace Members (your team):
Při propojování s členy pracovního prostoru (vaším týmem):
* Use their **email address**, not their name
* Example: `owner@yourcompany.com`, not "John Smith"
* Použijte jejich **e-mailovou adresu**, ne jméno
* Příklad: `owner@yourcompany.com`, ne "John Smith"
```csv
taskName,assignedTo
@@ -173,56 +173,56 @@ Follow up with client,john@yourcompany.com
Review proposal,jane@yourcompany.com
```
## FAQ
## Časté dotazy
<AccordionGroup>
<Accordion title="What if my parent record doesn't have a domain or email?">
You have two options:
<Accordion title="Co když můj nadřazený záznam nemá doménu ani e-mail?">
Máte dvě možnosti:
1. Use the Twenty `id` (export parent records to get their IDs)
2. Create a custom unique field in your data model to store an external ID from your previous system
1. Použijte Twenty `id` (exportujte nadřazené záznamy, abyste získali jejich ID)
2. Vytvořte ve svém datovém modelu vlastní jedinečné pole pro uložení externího ID z vašeho předchozího systému
</Accordion>
<Accordion title="Can I update relations on existing records?">
Ano! Include the child record's unique identifier (e.g., `email` for People) and the new relation value. The import will update the relation.
<Accordion title="Mohu aktualizovat relace u existujících záznamů?">
Ano! Zahrňte jedinečný identifikátor podřízeného záznamu (např. `email` u lidí) a novou hodnotu relace. Import relaci aktualizuje.
</Accordion>
<Accordion title="Can I import Many-to-Many relationships?">
Many-to-Many relations are not yet supported for import. This is planned for H1 2026.
<Accordion title="Mohu importovat vztahy mnoho k mnoha?">
Vztahy mnoho k mnoha zatím nejsou pro import podporovány. To je plánováno na 1. pololetí 2026.
</Accordion>
<Accordion title="Can I link to multiple object types (like Notes to People AND Companies)?">
Relations pointing to multiple object types are not yet supported for import/export. This is on our roadmap.
<Accordion title="Mohu propojovat s více typy objektů (například poznámky s lidmi A společnostmi)?">
Relace směřující k více typům objektů zatím nejsou pro import/export podporovány. Je to v našem plánu.
</Accordion>
<Accordion title="What happens if a parent record doesn't exist?">
The import will show an error for that row. Můžete buď:
<Accordion title="Co se stane, když nadřazený záznam neexistuje?">
Import u daného řádku zobrazí chybu. Můžete buď:
* Import the parent record first, then re-import
* Fix the reference value
* Remove the row from import
* Nejprve importujte nadřazený záznam, poté znovu importujte
* Opravte referenční hodnotu
* Odstraňte řádek z importu
</Accordion>
<Accordion title="Why is my relation not linking correctly?">
Common causes:
<Accordion title="Proč se moje relace nepropojuje správně?">
Časté příčiny:
* Wrong format (use `https://domain.com` for domains)
* Case mismatch (check exact spelling)
* Parent doesn't exist (import parents first)
* Mapping multiple identifiers (use only one)
* Nesprávný formát (pro domény použijte `https://domain.com`)
* Nesoulad ve velikosti písmen (zkontrolujte přesný zápis)
* Nadřazený neexistuje (nejprve importujte nadřazené)
* Mapujete více identifikátorů (použijte pouze jeden)
</Accordion>
</AccordionGroup>
<Warning>
**Remember: Soft-deleted records count toward uniqueness.**
**Pamatujte: Záznamy „soft-deleted“ se započítávají do jedinečnosti.**
If you're getting "not found" errors but the record seems to exist, check Command Menu → See deleted records. The parent may have been soft-deleted.
Pokud dostáváte chyby "not found", ale záznam se zdá existovat, zkontrolujte Command Menu → See deleted records. Nadřazený mohl být „soft-deleted.
</Warning>
## Řešení potíží
Having issues? Check:
Máte potíže? Podívejte se na:
* [How to Fix Import Errors](/l/cs/user-guide/data-migration/how-tos/fix-import-errors)
* [Import Relations Capabilities](/l/cs/user-guide/data-migration/capabilities/import-relations)
* [Uniqueness Constraints](/l/cs/user-guide/data-migration/capabilities/uniqueness-constraints)
* [Jak opravit chyby importu](/l/cs/user-guide/data-migration/how-tos/fix-import-errors)
* [Možnosti importu relací](/l/cs/user-guide/data-migration/capabilities/import-relations)
* [Omezení jedinečnosti](/l/cs/user-guide/data-migration/capabilities/uniqueness-constraints)
@@ -1,43 +1,43 @@
---
title: Migrace z jiných CRM
description: Step-by-step guide to migrate your data from any CRM to Twenty.
description: Podrobný průvodce krok za krokem pro migraci vašich dat z libovolného CRM do Twenty.
---
## Přehled
This guide walks you through migrating your data from any CRM to Twenty. The process involves auditing your data, preparing your Twenty workspace, exporting from your current system, and importing into Twenty.
Tento průvodce vás provede migrací vašich dat z libovolného CRM do Twenty. Proces zahrnuje audit vašich dat, přípravu vašeho pracovního prostoru Twenty, export z vašeho současného systému a import do Twenty.
<Note>Views, workflows, and permissions must be recreated manually after migration. Plan time for this configuration work.</Note>
<Note>Zobrazení, pracovní postupy a oprávnění je po migraci nutné vytvořit ručně. Naplánujte si čas na tuto konfigurační práci.</Note>
## Step 1: Audit Your Current Data
## Krok 1: Proveďte audit svých aktuálních dat
Migration is an opportunity for a fresh start. Don't bring over clutter.
Migrace je příležitostí k novému začátku. Nepřenášejte balast.
**What to keep:**
**Co ponechat:**
* Active contacts and companies
* Open opportunities and deals
* Important notes and activities
* Custom fields you actually use
* Aktivní kontakty a společnosti
* Otevřené obchodní příležitosti a obchody
* Důležité poznámky a aktivity
* Vlastní pole, která skutečně používáte
**What to leave behind:**
**Co nechat za sebou:**
* Outdated contacts (no activity in 2+ years)
* Duplicate records
* Test data
* Unused custom fields
* Zastaralé kontakty (bez aktivity 2 a více let)
* Duplicitní záznamy
* Testovací data
* Nepoužívaná vlastní pole
## Step 2: Map Your Data Model
## Krok 2: Zmapujte svůj datový model
Create a mapping document between your current CRM and Twenty:
Vytvořte mapovací dokument mezi vaším současným CRM a Twenty:
| Your CRM | Twenty |
| ---------------------- | -------------------- |
| Account / Organization | **Company** |
| Contact / Person | **People** |
| Deal / Opportunity | **Opportunity** |
| Activity | **Task** or **Note** |
| Custom Object | **Custom Object** |
| Vaše CRM | Twenty |
| -------------------- | -------------------- |
| Účet / organizace | **Společnost** |
| Kontakt / osoba | **Lidé** |
| Obchod / příležitost | **Příležitost** |
| Activity | **Task** or **Note** |
| Custom Object | **Custom Object** |
**For each field, document:**
@@ -1,71 +1,71 @@
---
title: Migrace z vlastních serverů do cloudu
description: Step-by-step guide to migrate your Twenty self-hosted instance to Twenty Cloud.
description: Podrobný průvodce krok za krokem pro migraci vaší instance Twenty hostované na vlastním serveru do Twenty Cloud.
---
## Přehled
This guide walks you through migrating your data from a Twenty self-hosted instance to Twenty Cloud. The process involves setting up your cloud workspace, exporting your data, and re-importing it.
Tento průvodce vás provede migrací vašich dat z instance Twenty hostované na vlastním serveru do Twenty Cloud. Proces zahrnuje zřízení vašeho cloudového pracovního prostoru, export dat a jejich opětovný import.
<Note>Views, workflows, and roles must be recreated manually after migration. Plan time for this configuration work.</Note>
<Note>Zobrazení, pracovní postupy a role je po migraci nutné vytvořit ručně. Naplánujte si čas na tuto konfigurační práci.</Note>
## Step 1: Create Your Cloud Workspace
## Krok 1: Vytvořte svůj cloudový pracovní prostor
1. Go to [app.twenty.com](https://app.twenty.com) and create a new workspace
2. Complete the initial setup wizard
3. Note your new workspace URL
1. Přejděte na [app.twenty.com](https://app.twenty.com) a vytvořte nový pracovní prostor
2. Dokončete úvodní nastavení pomocí průvodce
3. Poznamenejte si URL vašeho nového pracovního prostoru
## Step 2: Recreate Your Data Model
## Krok 2: Znovu vytvořte svůj datový model
Before importing data, recreate your custom objects and fields:
Před importem dat znovu vytvořte své vlastní objekty a pole:
1. Go to **Settings → Data Model** in your cloud instance
2. Create custom objects that match your self-hosted setup
3. Add custom fields to standard and custom objects
4. Configure field settings (unique, required, etc.)
1. Přejděte ve své cloudové instanci do **Settings → Data Model**
2. Vytvořte vlastní objekty, které odpovídají vašemu nastavení na vlastním serveru
3. Přidejte vlastní pole ke standardním i vlastním objektům
4. Nastavte vlastnosti polí (jedinečné, povinné apod.)
<Note>Take screenshots of your self-hosted data model for reference, or keep both instances open side by side.</Note>
<Note>Pořiďte si pro referenci snímky obrazovky vašeho datového modelu na vlastním serveru, nebo mějte obě instance otevřené vedle sebe.</Note>
## Step 3: Invite All Users
## Krok 3: Pozvěte všechny uživatele
<Warning>
**Critical: Invite users BEFORE importing data.**
**Důležité: Pozvěte uživatele PŘED importem dat.**
Users must accept their invitations before you import any records that reference them (like Account Owner fields). If users don't exist yet, those relations cannot be mapped.
Uživatelé musí přijmout své pozvánky, než importujete jakékoli záznamy, které na ně odkazují (například pole Account Owner). Pokud uživatelé ještě neexistují, tyto relace nelze namapovat.
</Warning>
1. Go to **Settings → Members** in your cloud instance
2. Invite all team members who had accounts on self-hosted
3. **Wait for everyone to accept** their invitation
4. Verify all users appear in your Members list
1. Přejděte ve své cloudové instanci do **Settings → Members**
2. Pozvěte všechny členy týmu, kteří měli účty v instanci hostované na vlastním serveru
3. **Počkejte, až všichni přijmou** své pozvání
4. Ověřte, že se všichni uživatelé zobrazují v seznamu Members
## Step 4: Export Data from Self-Hosted
## Krok 4: Export dat z instance hostované na vlastním serveru
Export each object from your self-hosted instance:
Exportujte každý objekt ze své instance hostované na vlastním serveru:
1. Navigate to each object (Companies, People, Opportunities, etc.)
2. Configure the view to show **all columns** you want to migrate
3. Click **⋮ → Export view**
4. Save each CSV file with a clear name (e.g., `companies-export.csv`)
1. Přejděte ke každému objektu (Společnosti, Lidé, Příležitosti atd.)
2. Nastavte zobrazení tak, aby zobrazovalo **všechny sloupce**, které chcete migrovat
3. Klikněte na **⋮ → Export view**
4. Uložte každý soubor CSV s jasným názvem (např. `companies-export.csv`)
**Export in this order** (for reference when importing):
**Exportujte v tomto pořadí** (pro referenci při importu):
1. Společnosti
2. Osoby
3. Příležitosti
4. Custom objects (following their dependencies)
5. Tasks, Notes
4. Vlastní objekty (podle jejich závislostí)
5. Úkoly, Poznámky
## Step 5: Update Workspace Member References
## Krok 5: Aktualizujte reference na členy pracovního prostoru
The exported CSVs contain user IDs from your self-hosted instance. These IDs won't match your cloud instance, so you need to replace them with emails.
Exportované soubory CSV obsahují ID uživatelů z vaší instance hostované na vlastním serveru. Tyto ID nebudou odpovídat vaší cloudové instanci, proto je musíte nahradit e-mailovými adresami.
**For each CSV file with user references (Owner, Assignee, etc.):**
**Pro každý soubor CSV s referencemi na uživatele (Owner, Assignee atd.):**
1. Open the CSV in a spreadsheet application
2. Add a new column next to each user ID column (e.g., `accountOwnerEmail` next to `accountOwnerId`)
3. Fill in the **email address** of each user
4. You can delete the old ID column or leave it (it will be skipped during import)
1. Otevřete soubor CSV v tabulkovém editoru
2. Přidejte nový sloupec vedle každého sloupce s ID uživatele (např. `accountOwnerEmail` vedle `accountOwnerId`)
3. Vyplňte **e-mailovou adresu** každého uživatele
4. Můžete starý sloupec s ID smazat, nebo ho ponechat (při importu bude přeskočen)
**Příklad:**
@@ -83,89 +83,89 @@ name,domain,accountOwnerEmail
Acme Corp,https://acme.com,john@yourcompany.com
```
<Note>Use the same email addresses that users used to accept their cloud workspace invitation.</Note>
<Note>Použijte stejné e-mailové adresy, které uživatelé použili k přijetí pozvánky do cloudového pracovního prostoru.</Note>
## Step 6: Plan Your Import Order
## Krok 6: Naplánujte pořadí importu
Import files in the correct order to maintain relationships:
Importujte soubory ve správném pořadí, abyste zachovali relace:
1. **Companies** first (no dependencies)
2. **People** second (link to Companies)
3. **Opportunities** third (link to Companies and People)
4. **Custom objects** (following their dependencies)
5. **Tasks and Notes** last (link to other records)
1. **Společnosti** jako první (bez závislostí)
2. **Lidé** jako druzí (propojení na společnosti)
3. **Příležitosti** jako třetí (propojené se společnostmi a lidmi)
4. **Vlastní objekty** (podle jejich závislostí)
5. **Úkoly a poznámky** nakonec (propojení na další záznamy)
See [How to Import Relations](/l/cs/user-guide/data-migration/how-tos/import-relations-between-objects-via-csv) for details on maintaining relationships.
Viz [Jak importovat relace](/l/cs/user-guide/data-migration/how-tos/import-relations-between-objects-via-csv) pro podrobnosti o zachování relací.
## Step 7: Import to Cloud
## Krok 7: Import do cloudu
For each CSV file, in order:
Pro každý soubor CSV, v daném pořadí:
1. Navigate to the object in your cloud instance
2. Click **⋮ → Import records**
3. Upload the CSV file
4. Map columns to fields:
* Map user email columns to the appropriate relation fields
* Map other columns as usual
5. Review and fix any errors
6. Confirm the import
7. Verify a few records before proceeding to the next file
1. Přejděte k objektu ve vaší cloudové instanci
2. Klikněte na **⋮ → Import records**
3. Nahrajte soubor CSV
4. Namapujte sloupce na pole:
* Namapujte sloupce s e-maily uživatelů na příslušná relační pole
* Ostatní sloupce namapujte obvyklým způsobem
5. Zkontrolujte a opravte případné chyby
6. Potvrďte import
7. Ověřte několik záznamů, než přejdete k dalšímu souboru
## Step 8: Recreate Configuration
## Krok 8: Znovu vytvořte konfiguraci
After importing data, manually recreate:
Po importu dat ručně znovu vytvořte:
### Zobrazení
* Recreate saved views with filters, sorts, and column configurations
* Set up any kanban or calendar views
* Znovu vytvořte uložená zobrazení s filtry, řazením a nastavením sloupců
* Nastavte případná kanbanová nebo kalendářová zobrazení
### Pracovní postupy
* Recreate automations in **Settings → Workflows**
* Test each workflow before relying on it
* Znovu vytvořte automatizace v **Settings → Workflows**
* Otestujte každý pracovní postup, než se na něj spolehnete
### Roles and Permissions
### Role a oprávnění
* Configure roles in **Settings → Roles**
* Assign users to appropriate roles
* Nakonfigurujte role v **Settings → Roles**
* Přiřaďte uživatele ke vhodným rolím
### Integrace
* Reconnect email and calendar sync for each user
* Reconfigure any API integrations with new API keys
* Znovu připojte synchronizaci e-mailu a kalendáře pro každého uživatele
* Znovu nakonfigurujte případné integrace API s novými klíči API
## Post-migrační kontrolní seznam
<Check>All data imported successfully</Check>
<Check>Relations between objects working correctly</Check>
<Check>User assignments (Owner, Assignee) mapped correctly</Check>
<Check>Views recreated</Check>
<Check>Workflows recreated and tested</Check>
<Check>Roles and permissions configured</Check>
<Check>Email/calendar sync reconnected</Check>
<Check>API integrations updated with new keys</Check>
<Check>Všechna data byla úspěšně importována</Check>
<Check>Relace mezi objekty fungují správně</Check>
<Check>Přiřazení uživatelů (Owner, Assignee) je namapováno správně</Check>
<Check>Zobrazení znovu vytvořena</Check>
<Check>Pracovní postupy znovu vytvořeny a otestovány</Check>
<Check>Role a oprávnění nakonfigurovány</Check>
<Check>Synchronizace e-mailu/kalendáře znovu připojena</Check>
<Check>Integrace API aktualizovány s novými klíči</Check>
## FAQ
## Časté dotazy
<AccordionGroup>
<Accordion title="Can I migrate workflows automatically?">
Not currently. Workflows must be recreated manually in your cloud instance.
<Accordion title="Mohu migrovat pracovní postupy automaticky?">
V tuto chvíli ne. Pracovní postupy je nutné ve vaší cloudové instanci znovu vytvořit ručně.
</Accordion>
<Accordion title="What about file attachments and images?">
File attachments are not included in CSV exports. You'll need to re-upload any attachments manually, migrate them via API or contact our team for assistance with large migrations.
<Accordion title="A co přílohy a obrázky?">
Přílohy nejsou součástí exportů CSV. Přílohy budete muset nahrát znovu ručně, migrovat je přes API nebo kontaktovat náš tým pro pomoc s rozsáhlými migracemi.
</Accordion>
<Accordion title="Can I keep both instances running during migration?">
Yes, we recommend keeping your self-hosted instance running until you've verified the cloud migration is complete. Just be careful not to create new data in both places.
<Accordion title="Mohu během migrace ponechat obě instance v provozu?">
Ano, doporučujeme ponechat vaši instanci na vlastním serveru v provozu, dokud neověříte, že migrace do cloudu je dokončena. Jen si dejte pozor, abyste nevytvářeli nová data na obou místech.
</Accordion>
<Accordion title="What if a user hasn't accepted their invitation yet?">
Records referencing that user will fail to import or the relation will be empty. Ensure all users accept invitations before importing data.
<Accordion title="Co když uživatel ještě nepřijal svou pozvánku?">
Záznamy, které na daného uživatele odkazují, se nepodaří importovat, nebo bude relace prázdná. Ujistěte se, že všichni uživatelé přijali pozvánky před importem dat.
</Accordion>
</AccordionGroup>
## Potřebujete pomoc?
For complex migrations or large datasets, contact us at [contact@twenty.com](mailto:contact@twenty.com) or explore our [Implementation Services](/l/cs/user-guide/getting-started/capabilities/implementation-services).
U složitých migrací nebo velkých datových sad nás kontaktujte na [contact@twenty.com](mailto:contact@twenty.com) nebo si prohlédněte naše [Implementační služby](/l/cs/user-guide/getting-started/capabilities/implementation-services).
@@ -42,10 +42,6 @@ Oblíbené jsou záznamy, které jste označili pro rychlý přístup, objevují
A field refers to a specific area where particular data is stored for an entity.
## Integrace
Integrations are built-in tools that allow you to link Twenty with other software or systems.
## Iterátor
An Iterator is a workflow action that loops through an array of items, executing subsequent actions for each item in the list.
@@ -34,7 +34,7 @@ Pokud jste tak neučinili při vytváření svého pracovního prostoru, připoj
* Udržujte historii komunikace viditelnou pro váš tým
**Používáte jiného poskytovatele?**
Můžete přidat jinou poštovní schránku přes SMTP nebo jiný kalendář přes CalDAV. Budete muset aktivovat tuto funkci v Nastavení → Verze → Laboratoře, a poté se vrátit na kartu Nastavení → Účty.
Můžete přidat jinou poštovní schránku přes SMTP nebo jiný kalendář přes CalDAV. Go to **Settings → Accounts** to configure.
### Importujte data pomocí csv
@@ -20,7 +20,6 @@ On the left side, from the top to the bottom, you'll be able to:
* Mějte přímý přístup ke svým **oblíbeným zobrazením**. Oblíbené jsou unikátní pro každého uživatele.
* Přepínejte mezi různými objekty
* **Create automations** using workflows
* Kontaktujte podporu a otevřete naši uživatelskou příručku.
<img src="/images/user-guide/home/navigation-bar.png" style={{width:'100%'}} />
@@ -78,6 +77,8 @@ Open your Settings from the top left to:
* Pozvěte členy týmu a spravujte role uživatelů
* Upravte svůj profil a preference pracovního prostoru
* Configure billing and monitor workflow credits usage
* Objevte nejnovější vydání a připravované funkce (v části Vydáníkarta Lab)
* Discover and enable upcoming features (under UpdatesEarly Access)
* **Access Support** to reach out via live chat
* **Open the Documentation** to browse the User Guide and developer docs
<Note>If you do not see all those sections under Settings, reach out to your workspace administrator - some of them have restricted access.</Note>
@@ -1,63 +1,63 @@
---
title: Discover Twenty
description: Welcome to Twenty User Guide, your resources for advanced configurations and best practices.
title: Objevte Twenty
description: Vítejte v uživatelské příručce Twenty, která je vaším zdrojem pokročilých konfigurací a osvědčených postupů.
---
import { CardTitle } from "/snippets/card-title.mdx"
<CardGroup cols={3}>
<Card href="/l/cs/user-guide/getting-started/capabilities/what-is-twenty" img="/images/user-guide/api/api.png">
<CardTitle>Discover Twenty</CardTitle>
Learn what Twenty is and how it can help your business.
<CardTitle>Objevte Twenty</CardTitle>
Zjistěte, co je Twenty a jak může pomoci vašemu podnikání.
</Card>
<Card href="/l/cs/user-guide/data-model/overview" img="/images/user-guide/fields/custom_data_model.png">
<CardTitle>Data Model</CardTitle>
Customize your data model to fit your business processes.
<CardTitle>Datový model</CardTitle>
Přizpůsobte svůj datový model tak, aby odpovídal vašim obchodním procesům.
</Card>
<Card href="/l/cs/user-guide/data-migration/overview" img="/images/user-guide/import-export-data/cloud.png">
<CardTitle>Data Migration</CardTitle>
Import and export your data via CSV or API.
<CardTitle>Migrace dat</CardTitle>
Importujte a exportujte svá data pomocí CSV nebo API.
</Card>
<Card href="/l/cs/user-guide/calendar-emails/overview" img="/images/user-guide/emails/emails_header.png">
<CardTitle>Calendar & Emails</CardTitle>
Centralize your team's meetings and emails.
<CardTitle>Kalendář a e-maily</CardTitle>
Centralizujte schůzky a e-maily svého týmu.
</Card>
<Card href="/l/cs/user-guide/workflows/overview" img="/images/user-guide/workflows/workflow.png">
<CardTitle>Workflows</CardTitle>
Automate processes and integrate with external tools.
<CardTitle>Pracovní postupy</CardTitle>
Automatizujte procesy a integrujte se s externími nástroji.
</Card>
<Card href="/l/cs/user-guide/ai/overview" img="/images/user-guide/workflows/robot.png">
<CardTitle>AI</CardTitle>
Enhance your team with AI agents.
Posilte svůj tým pomocí agentů AI.
</Card>
<Card href="/l/cs/user-guide/views-pipelines/overview" img="/images/user-guide/table-views/table_pink.png">
<CardTitle>Views & Pipelines</CardTitle>
Organize your data with actionable views and pipelines.
<CardTitle>Zobrazení a pipeline</CardTitle>
Uspořádejte svá data pomocí praktických zobrazení a pipeline.
</Card>
<Card href="/l/cs/user-guide/dashboards/overview" img="/images/user-guide/reporting/pie-chart.png">
<CardTitle>Dashboards</CardTitle>
Real-time insights to track performance.
<CardTitle>Přehledy</CardTitle>
Informace v reálném čase pro sledování výkonnosti.
</Card>
<Card href="/l/cs/user-guide/permissions-access/overview" img="/images/user-guide/permissions/permissions.png">
<CardTitle>Permissions & Access</CardTitle>
Manage roles and access to Twenty.
<CardTitle>Oprávnění a přístup</CardTitle>
Spravujte role a přístup k Twenty.
</Card>
<Card href="/l/cs/user-guide/billing/overview" img="/images/user-guide/setup/pricing.png">
<CardTitle>Billing</CardTitle>
Understand how Twenty pricing and billing works.
<CardTitle>Fakturace</CardTitle>
Pochopte, jak fungují ceny a fakturace Twenty.
</Card>
<Card href="/l/cs/user-guide/settings/overview" img="/images/user-guide/setup/settings.png">
<CardTitle>Settings</CardTitle>
Configure your workspace preferences.
<CardTitle>Nastavení</CardTitle>
Nastavte předvolby svého pracovního prostoru.
</Card>
</CardGroup>
@@ -1,126 +1,126 @@
---
title: Permissions FAQ
description: Frequently asked questions about roles and permissions.
title: Nejčastější dotazy k oprávněním
description: Často kladené otázky týkající se rolí a oprávnění.
---
## Role
<AccordionGroup>
<Accordion title="What roles come with Twenty by default?">
Twenty comes with an **Admin** and **Member** roles by default. You can create additional custom roles based on your team's needs (e.g., Sales Rep, Manager, Read-Only User).
<Accordion title="Jaké role jsou ve Twenty ve výchozím nastavení?">
Twenty ve výchozím stavu obsahuje role **Administrátor** a **Člen**. Můžete vytvářet další vlastní role podle potřeb vašeho týmu (např. obchodní zástupce, manažer, uživatel pouze pro čtení).
</Accordion>
<Accordion title="Can I delete the Admin role?">
No, the Admin role cannot be deleted. There must always be at least one member assigned to the Admin role.
<Accordion title="Mohu smazat roli Administrátor?">
Ne, roli Administrátor nelze smazat. Musí být vždy alespoň jeden člen přiřazen k roli Administrátor.
</Accordion>
<Accordion title="What happens when I delete a role?">
Any workspace member assigned to that role will be automatically reassigned to the default role.
<Accordion title="Co se stane, když smažu roli?">
Každý člen pracovního prostoru přiřazený k této roli bude automaticky přeřazen na výchozí roli.
</Accordion>
<Accordion title="How do I set a default role for new members?">
Go to **Settings → Roles**, find the **Default Role** option, and select which role new members should automatically receive when they join.
<Accordion title="Jak nastavím výchozí roli pro nové členy?">
Přejděte do **Nastavení → Role**, najděte možnost **Výchozí role** a vyberte, kterou roli mají noví členové po připojení automaticky získat.
</Accordion>
<Accordion title="Can I assign multiple roles to one user?">
No, each user can only have one role at a time. Create a custom role if you need a combination of permissions.
<Accordion title="Mohu jednomu uživateli přiřadit více rolí?">
Ne, každý uživatel může mít najednou pouze jednu roli. Pokud potřebujete kombinaci oprávnění, vytvořte vlastní roli.
</Accordion>
</AccordionGroup>
## Oprávnění
<AccordionGroup>
<Accordion title="What's the difference between object and field permissions?">
* **Object permissions**: Control access to entire records (e.g., can see/edit/delete People records)
* **Field permissions**: Control access to specific fields within an object (e.g., can see but not edit the Salary field)
<Accordion title="Jaký je rozdíl mezi oprávněními objektu a pole?">
* **Oprávnění objektu**: Řídí přístup k celým záznamům (např. může zobrazovat/upravovat/mazat záznamy People)
* **Oprávnění pole**: Řídí přístup ke konkrétním polím v rámci objektu (např. může vidět pole Salary, ale nemůže ho upravovat)
Field permissions allow more granular control over sensitive data.
Oprávnění na úrovni pole umožňují podrobnější kontrolu nad citlivými daty.
</Accordion>
<Accordion title="How do permission overrides work?">
Permissions cascade from global to specific:
<Accordion title="Jak fungují přepsání oprávnění?">
Oprávnění se kaskádovitě aplikují od globálních ke specifickým:
1. **All Objects** sets the baseline for all objects
2. **Object-Level Permissions** can override the global setting for specific objects
3. **Field-Level Permissions** can override the object setting for specific fields
1. **Všechny objekty** určují základní nastavení pro všechny objekty
2. **Oprávnění na úrovni objektu** mohou přepsat globální nastavení pro konkrétní objekty
3. **Oprávnění na úrovni pole** mohou přepsat nastavení objektu pro konkrétní pole
More specific settings always take precedence.
Specifičtější nastavení mají vždy přednost.
</Accordion>
<Accordion title="What do the different permission levels mean?">
For objects:
<Accordion title="Co znamenají jednotlivé úrovně oprávnění?">
Pro objekty:
* **See Records**: View records in lists and detail pages
* **Edit Records**: Modify existing records
* **Delete Records**: Soft-delete records (can be restored)
* **Destroy Records**: Permanently delete records
* **Zobrazit záznamy**: Zobrazit záznamy v seznamech a na detailních stránkách
* **Upravit záznamy**: Upravit existující záznamy
* **Smazat záznamy**: Dočasně smazat záznamy (lze obnovit)
* **Trvale odstranit záznamy**: Trvale smazat záznamy
For fields:
Pro pole:
* **See Field**: View the field value
* **Edit Field**: Modify the field value
* **No Access**: Field is completely hidden
* **Zobrazit pole**: Zobrazit hodnotu pole
* **Upravit pole**: Změnit hodnotu pole
* **Bez přístupu**: Pole je zcela skryté
</Accordion>
<Accordion title="Can I restrict access to specific records (row-level permissions)?">
Row-level permissions will be available on the **Organization** plan by Q1 2026. This allows you to restrict access to specific records based on criteria (e.g., only see your own opportunities).
<Accordion title="Mohu omezit přístup ke konkrétním záznamům (oprávnění na úrovni řádků)?">
Oprávnění na úrovni řádků budou k dispozici v tarifu **Organization** v 1. čtvrtletí 2026. To umožní omezit přístup ke konkrétním záznamům na základě kritérií (např. zobrazovat pouze vlastní příležitosti).
</Accordion>
<Accordion title="How do I make a field read-only for certain users?">
<Accordion title="Jak nastavím pole jen pro čtení pro určité uživatele?">
1. Přejděte na **Nastavení → Role**
2. Select the role
3. Navigate to the object containing the field
4. Set the field permission to **See Field** (without Edit Field)
2. Vyberte roli
3. Přejděte k objektu, který pole obsahuje
4. Nastavte oprávnění pole na **Zobrazit pole** (bez Upravit pole)
</Accordion>
</AccordionGroup>
## Settings & Actions
## Nastavení a akce
<AccordionGroup>
<Accordion title="What settings permissions are available?">
You can control access to:
<Accordion title="Jaká oprávnění k nastavení jsou k dispozici?">
Můžete řídit přístup k:
* API key generation
* Workspace preferences
* Role assignment
* Data model configuration
* Security settings
* Workflow management
* Generování klíčů API
* Předvolby pracovního prostoru
* Přiřazování rolí
* Konfigurace datového modelu
* Nastavení zabezpečení
* Správa pracovních postupů
Use **Settings All Access** to grant full access, or enable specific permissions.
Použijte **Settings All Access** pro udělení plného přístupu, nebo povolte konkrétní oprávnění.
</Accordion>
<Accordion title="What action permissions are available?">
You can control:
<Accordion title="Jaká oprávnění k akcím jsou k dispozici?">
Můžete řídit:
* **Send Email**: Ability to send emails from Twenty
* **Import CSV**: Ability to import data via CSV
* **Export CSV**: Ability to export data to CSV
* **Odeslat e-mail**: Možnost odesílat e-maily z Twenty
* **Import CSV**: Možnost importovat data přes CSV
* **Export CSV**: Možnost exportovat data do CSV
Use **Application All Access** to grant all actions, or enable specific ones.
Použijte **Application All Access** k povolení všech akcí, nebo povolte jen konkrétní.
</Accordion>
</AccordionGroup>
## Jednotné přihlášení
<AccordionGroup>
<Accordion title="Is SSO available on all plans?">
No, SSO is a Premium feature available on the **Organization** plan only.
<Accordion title="Je SSO dostupné ve všech tarifech?">
Ne, SSO je prémiová funkce dostupná pouze v tarifu **Organization**.
</Accordion>
<Accordion title="Which identity providers are supported?">
Twenty supports:
<Accordion title="Kteří poskytovatelé identity jsou podporováni?">
Twenty podporuje:
* **SAML 2.0** (works with most enterprise identity providers)
* **SAML 2.0** (funguje s většinou podnikových poskytovatelů identity)
* **Google Workspace**
* **Microsoft Entra ID** (formerly Azure AD)
* **Microsoft Entra ID** (dříve Azure AD)
</Accordion>
<Accordion title="What is Just-in-Time (JIT) provisioning?">
With JIT provisioning, user accounts are automatically created in Twenty when someone logs in via SSO for the first time. They're assigned the default role automatically.
<Accordion title="Co je zřizování Just-in-Time (JIT)?">
Při zřizování JIT se uživatelské účty v Twenty vytvoří automaticky, když se někdo poprvé přihlásí přes SSO. Automaticky jim je přiřazena výchozí role.
</Accordion>
<Accordion title="Can I require SSO for all users?">
Yes, once SSO is configured, you can disable password login for SSO users to enforce authentication through your identity provider.
<Accordion title="Mohu vyžadovat SSO pro všechny uživatele?">
Ano, jakmile je SSO nakonfigurováno, můžete pro uživatele SSO zakázat přihlášení heslem a vynutit ověřování přes vašeho poskytovatele identity.
</Accordion>
</AccordionGroup>
@@ -0,0 +1,36 @@
---
title: Updates Settings
description: Enable Early Access features in Twenty.
---
## About Updates Settings
The Updates section allows you to enable Early Access features before they're generally available.
## Early Access Features
Early Access features are capabilities that are still being tested before general availability.
**Currently in Early Access:**
* **Dashboards** — Visual reporting and analytics
### How to Enable Early Access Features
1. Go to **Settings → Updates**
2. Navigate to the **Early Access** section
3. Find the feature you want to enable
4. Toggle it on
5. The feature will be available immediately
<Note>
Early Access features may change based on user feedback. Your input helps us improve Twenty!
</Note>
## Feature Feedback
Your feedback helps improve Twenty:
* Report issues with Early Access features
* Share how you're using new features
* Suggest improvements via the community Discord
@@ -1,136 +1,136 @@
---
title: Nastavení FAQ
description: Frequently asked questions about Twenty settings.
description: Často kladené otázky k nastavení Twenty.
image: /images/user-guide/setup/settings.png
---
## Nastavení pracovního prostoru
<AccordionGroup>
<Accordion title="How do I change my workspace name?">
1. Go to **Settings → General**
2. Find the Workspace Name field
3. Enter your new name
4. Changes save automatically
<Accordion title="Jak změním název svého pracovního prostoru?">
1. Přejděte na **Nastavení → Obecné**
2. Najděte pole Název pracovního prostoru
3. Zadejte nový název
4. Změny se ukládají automaticky
</Accordion>
<Accordion title="How do I update my workspace logo?">
1. Go to **Settings → General**
2. Click on the current logo or upload area
3. Select an image file (PNG, JPEG, or GIF under 10MB)
4. The logo updates immediately
<Accordion title="Jak změním logo svého pracovního prostoru?">
1. Přejděte na **Nastavení → Obecné**
2. Klikněte na aktuální logo nebo na oblast pro nahrání
3. Vyberte soubor s obrázkem (PNG, JPEG nebo GIF do 10 MB)
4. Logo se aktualizuje okamžitě
</Accordion>
<Accordion title="Can I have multiple workspaces?">
Yes, you can create and be a member of multiple workspaces. Each workspace has its own data, settings, and subscription.
<Accordion title="Mohu mít více pracovních prostorů?">
Ano, můžete vytvářet a být členem více pracovních prostorů. Každý pracovní prostor má vlastní data, nastavení a předplatné.
</Accordion>
<Accordion title="How do I delete my workspace?">
1. Go to **Settings → General**
2. Scroll to Danger Zone
3. Click **Delete workspace**
4. Confirm the deletion
<Accordion title="Jak smažu svůj pracovní prostor?">
1. Přejděte na **Nastavení → Obecné**
2. Přejděte na sekci Nebezpečná zóna
3. Klikněte na **Smazat pracovní prostor**
4. Potvrďte smazání
Note: This permanently deletes all data and cannot be undone.
Poznámka: Tímto trvale smažete všechna data a akci nelze vrátit zpět.
</Accordion>
<Accordion title="I accidentally created multiple workspaces. Co mám dělat?">
Delete the workspaces you no longer need under **Settings → General → Delete workspace**.
<Accordion title="Omylem jsem vytvořil více pracovních prostorů. Co mám dělat?">
Smažte pracovní prostory, které již nepotřebujete, v části **Nastavení → Obecné → Smazat pracovní prostor**.
<Warning>
Do not delete your **account** (accessible under Settings → Profile): your account is shared among all your workspaces. Deleting your account removes access to ALL workspaces.
Nemažte svůj **účet** (přístupný v Nastavení → Profil): váš účet je sdílen mezi všemi vašimi pracovními prostory. Smazáním účtu ztratíte přístup ke VŠEM pracovním prostorům.
</Warning>
</Accordion>
<Accordion title="How do I disable my workspace without deleting it?">
If you want to temporarily disable your workspace (not permanently delete it), go to **Settings → Billing** and click **Cancel Plan**. Your data will be preserved for a grace period.
<Accordion title="Jak mohu deaktivovat svůj pracovní prostor, aniž by došlo k jeho smazání?">
Pokud chcete dočasně deaktivovat svůj pracovní prostor (ne ho trvale smazat), přejděte do **Nastavení → Fakturace** a klikněte na **Zrušit plán**. Vaše data budou po přechodnou dobu zachována.
</Accordion>
</AccordionGroup>
## Nastavení profilu
<AccordionGroup>
<Accordion title="How do I change my password?">
1. Go to **Settings → Profile**
2. Find the Password section
3. Enter your current password
4. Enter your new password
5. Save changes
<Accordion title="Jak změním své heslo?">
1. Přejděte na **Nastavení → Profil**
2. Najděte sekci Heslo
3. Zadejte své stávající heslo
4. Zadejte své nové heslo
5. Uložte změny
</Accordion>
<Accordion title="How do I enable two-factor authentication?">
1. Go to **Settings → Profile**
2. Find the 2FA section
<Accordion title="Jak zapnu dvoufaktorové ověřování?">
1. Přejděte na **Nastavení → Profil**
2. Najděte sekci 2FA
3. Klikněte na **Povolit 2FA**
4. Naskenujte QR kód pomocí vaší autentizační aplikace
5. Enter the verification code
5. Zadejte ověřovací kód
</Accordion>
<Accordion title="Can I change my email address?">
To change your email address, please reach out to [contact@twenty.com](mailto:contact@twenty.com).
<Accordion title="Mohu změnit svou e-mailovou adresu?">
Chcete-li změnit svou e-mailovou adresu, kontaktujte prosím [contact@twenty.com](mailto:contact@twenty.com).
</Accordion>
<Accordion title="How do I delete my account?">
1. Go to **Settings → Profile**
2. Scroll to Danger Zone
<Accordion title="Jak smažu svůj účet?">
1. Přejděte na **Nastavení → Profil**
2. Přejděte na sekci Nebezpečná zóna
3. Klikněte na **Smazat účet**
4. Confirm by typing your email
4. Potvrďte zadáním své e-mailové adresy
Note: This removes your access to all workspaces and deletes all emails synced from your connected accounts.
Poznámka: Tímto ztratíte přístup ke všem pracovním prostorům a smažou se všechny e-maily synchronizované z vašich propojených účtů.
</Accordion>
</AccordionGroup>
## Nastavení prostředí
<AccordionGroup>
<Accordion title="How do I switch between light and dark mode?">
1. Go to **Settings → Experience**
2. Find the Theme section
3. Select Light, Dark, or System
<Accordion title="Jak přepnout mezi světlým a tmavým režimem?">
1. Přejděte do **Nastavení → Prostředí**
2. Najděte sekci Téma
3. Vyberte Světlý, Tmavý nebo Systémový
</Accordion>
<Accordion title="How do I change the date format?">
1. Go to **Settings → Experience**
2. Find Date Format
3. Select your preferred format
4. Changes apply immediately
<Accordion title="Jak změním formát data?">
1. Přejděte do **Nastavení → Prostředí**
2. Najděte Formát data
3. Vyberte preferovaný formát
4. Změny se projeví okamžitě
</Accordion>
<Accordion title="How do I change my time zone?">
1. Go to **Settings → Experience**
2. Find Time Zone
3. Select your local time zone
4. All timestamps will adjust
<Accordion title="Jak změním své časové pásmo?">
1. Přejděte do **Nastavení → Prostředí**
2. Najděte Časové pásmo
3. Vyberte své místní časové pásmo
4. Všechny časové údaje se přizpůsobí
</Accordion>
<Accordion title="Can I change the language?">
1. Go to **Settings → Experience**
2. Find Language
3. Select from available languages
4. The interface updates to your selection
<Accordion title="Mohu změnit jazyk?">
1. Přejděte do **Nastavení → Prostředí**
2. Najděte Jazyk
3. Vyberte z dostupných jazyků
4. Rozhraní se podle vašeho výběru aktualizuje
</Accordion>
</AccordionGroup>
## Account Settings
## Nastavení účtu
<AccordionGroup>
<Accordion title="How do I connect my email account?">
<Accordion title="Jak připojím svůj e-mailový účet?">
1. Přejděte na **Nastavení → Účty**
2. Klikněte na **Přidat účet**
3. Choose Google or Microsoft
4. Authorize access
5. Configure sync settings
3. Zvolte Google nebo Microsoft
4. Povolte přístup
5. Nakonfigurujte nastavení synchronizace
</Accordion>
<Accordion title="Can I connect multiple email accounts?">
Yes, you can connect multiple email accounts. Go to **Settings → Accounts** and add additional accounts as needed.
<Accordion title="Mohu připojit více e-mailových účtů?">
Ano, můžete připojit více e-mailových účtů. Přejděte do **Nastavení → Účty** a podle potřeby přidejte další účty.
</Accordion>
<Accordion title="How do I disconnect an email account?">
<Accordion title="Jak odpojím e-mailový účet?">
1. Přejděte na **Nastavení → Účty**
2. Find the account to remove
3. Click **Disconnect**
4. Confirm the action
2. Najděte účet, který chcete odebrat
3. Klikněte na **Odpojit**
4. Potvrďte akci
</Accordion>
</AccordionGroup>
@@ -138,34 +138,34 @@ image: /images/user-guide/setup/settings.png
<AccordionGroup>
<Accordion title="Mohu přizpůsobit doménu své pracovní oblasti?">
Ano! Go to **Settings → Domains** and click **Customize Domain**. You have two options:
Ano! Přejděte do **Nastavení → Domény** a klikněte na **Přizpůsobit doménu**. Máte dvě možnosti:
* **Subdomain**: Use a Twenty subdomain like `yourcompany.twenty.com`
* **Custom domain**: Use your own domain like `crm.yourcompany.com` (requires DNS configuration)
* **Poddoména**: Použijte poddoménu Twenty, například `yourcompany.twenty.com`
* **Vlastní doména**: Použijte svou vlastní doménu, například `crm.yourcompany.com` (vyžaduje konfiguraci DNS)
A subdomain is quick to set up, while a custom domain provides a fully branded experience for your team.
Poddoménu nastavíte rychle, zatímco vlastní doména poskytne vašemu týmu plně brandované prostředí.
</Accordion>
<Accordion title="How do approved access domains work?">
You can configure approved access domains so team members with company email addresses can automatically join your workspace. Go to **Settings → Domains** and add your company domain (e.g., `yourcompany.com`).
<Accordion title="Jak fungují schválené přístupové domény?">
Můžete nastavit schválené přístupové domény tak, aby se členové týmu s firemními e-mailovými adresami mohli automaticky připojit k vašemu pracovnímu prostoru. Přejděte do **Nastavení → Domény** a přidejte svou firemní doménu (např. `yourcompany.com`).
</Accordion>
</AccordionGroup>
## Funkce v Labu
## Early Access Features
<AccordionGroup>
<Accordion title="What are Lab features?">
Lab features are experimental capabilities being tested before general release. They may change or be removed without notice.
<Accordion title="What are Early Access features?">
Early Access features are capabilities being tested before general release. Currently, only **Dashboards** are in Early Access. They may change based on user feedback.
</Accordion>
<Accordion title="Are Lab features safe to use?">
Lab features are functional but may have bugs or unexpected behavior. Use them cautiously in production environments.
<Accordion title="Are Early Access features safe to use?">
Early Access features are functional but may change based on user feedback. They are safe to use but may evolve before general availability.
</Accordion>
<Accordion title="How do I enable Lab features?">
1. Go to **Settings → Releases → Lab**
2. Find the feature you want
3. Toggle it on
4. The feature becomes available immediately
<Accordion title="How do I enable Early Access features?">
1. Go to **Settings → Updates → Early Access**
2. Najděte požadovanou funkci
3. Přepněte ji na zapnuto
4. Funkce se okamžitě zpřístupní
</Accordion>
</AccordionGroup>
@@ -1,6 +1,6 @@
---
title: Nastavení
description: Set up your Twenty workspace with essential configurations.
description: Nastavte svůj pracovní prostor Twenty pomocí klíčových nastavení.
image: /images/user-guide/setup/settings.png
---
@@ -8,60 +8,60 @@ image: /images/user-guide/setup/settings.png
<img src="/images/user-guide/setup/settings.png" alt="Nastavení" />
</Frame>
## Initial Setup
## Úvodní nastavení
When you first create your workspace, there are several key settings to configure.
Když poprvé vytvoříte svůj pracovní prostor, je třeba nakonfigurovat několik klíčových nastavení.
### Workspace Name and Logo
### Název pracovního prostoru a logo
1. Go to **Settings → General**
2. Update your workspace name
3. Upload your company logo
4. Save your changes
1. Přejděte na **Nastavení → Obecné**
2. Aktualizujte název svého pracovního prostoru
3. Nahrajte logo své společnosti
4. Uložte změny
### Time Zone and Date Format
### Časové pásmo a formát data
1. Go to **Settings → Experience**
2. Select your time zone
3. Choose your preferred date format
4. Save your changes
1. Přejděte do **Nastavení → Prostředí**
2. Vyberte své časové pásmo
3. Zvolte preferovaný formát data
4. Uložte změny
## Essential Configurations
## Zásadní nastavení
### Connect Email and Calendar
### Propojte e-mail a kalendář
Set up email and calendar sync:
Nastavte synchronizaci e-mailů a kalendáře:
1. Přejděte na **Nastavení → Účty**
2. Klikněte na **Přidat účet**
3. Connect your Google or Microsoft account
4. Configure sync settings
3. Připojte svůj účet Google nebo Microsoft
4. Nakonfigurujte nastavení synchronizace
→ [Complete email & calendar setup guide](/l/cs/user-guide/calendar-emails/overview)
→ [Kompletní průvodce nastavením e-mailu a kalendáře](/l/cs/user-guide/calendar-emails/overview)
### Invite Your Team
### Pozvěte svůj tým
Add team members to your workspace:
Přidejte členy týmu do svého pracovního prostoru:
1. Přejděte na **Nastavení → Členové**
2. Click **+ Invite**
3. Enter email addresses
4. Assign appropriate roles
2. Klikněte na **+ Pozvat**
3. Zadejte e-mailové adresy
4. Přiřaďte příslušné role
<Note>
Before inviting your team, check the default role under **Settings → Roles**. New members are automatically assigned this role when they join.
Před pozváním týmu zkontrolujte výchozí roli v **Nastavení → Role**. Novým členům je tato role automaticky přiřazena, když se připojí.
</Note>
## Workspace Settings Checklist
## Kontrolní seznam nastavení pracovního prostoru
* Workspace name and logo configured
* Time zone and date format set
* Email and calendar connected
* Team members invited
* Roles and permissions configured
* Název a logo pracovního prostoru nastaveny
* Časové pásmo a formát data nastaveny
* E-mail a kalendář propojeny
* Členové týmu pozváni
* Role a oprávnění nakonfigurovány
## Další kroky
* [Workspace settings](/l/cs/user-guide/settings/capabilities/workspace-settings)
* [Profile settings](/l/cs/user-guide/settings/capabilities/profile-settings)
* [Experience settings](/l/cs/user-guide/settings/capabilities/experience-settings)
* [Nastavení pracovního prostoru](/l/cs/user-guide/settings/capabilities/workspace-settings)
* [Nastavení profilu](/l/cs/user-guide/settings/capabilities/profile-settings)
* [Nastavení prostředí](/l/cs/user-guide/settings/capabilities/experience-settings)
@@ -1,120 +1,120 @@
---
title: Set Up a Sales Pipeline
description: Configure your sales pipeline to track opportunities through stages.
title: Nastavte prodejní pipeline
description: Nakonfigurujte svou prodejní pipeline pro sledování příležitostí napříč fázemi.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
A sales pipeline in Twenty is a Kanban view of your Opportunities object, where each column represents a stage in your sales process.
Prodejní pipeline v Twenty je kanbanové zobrazení vašeho objektu Příležitosti, kde každý sloupec představuje fázi ve vašem prodejním procesu.
## Step 1: Configure Your Stages
## Krok 1: Nakonfigurujte své fáze
Stages are defined in the Opportunities object's **Stage** field.
Fáze jsou definovány v objektu Příležitosti v poli **Stage**.
1. Go to **Settings → Data Model**
2. Select **Opportunities**
3. Find and click the **Stage** field
4. Add, remove, or rename stages to match your process
1. Přejděte na **Nastavení → Datový model**
2. Vyberte **Příležitosti**
3. Najděte a klikněte na pole **Stage**
4. Přidejte, odeberte nebo přejmenujte fáze tak, aby odpovídaly vašemu procesu
<VimeoEmbed videoId="927890428" title="Video demonstration" />
<VimeoEmbed videoId="927890428" title="Ukázka videa" />
### Recommended Stages
### Doporučené fáze
| Fáze | Purpose |
| --------------- | ----------------------------------- |
| **New** | Fresh opportunities just identified |
| **Qualified** | Confirmed as a good fit |
| **Meeting** | Engaged in discussions |
| **Proposal** | Proposal sent |
| **Negotiation** | Working on terms |
| **Closed Won** | Deal successful |
| **Closed Lost** | Deal unsuccessful |
| Fáze | Účel |
| ----------------------- | -------------------------------- |
| **Nový** | Nově identifikované příležitosti |
| **Kvalifikovaný** | Potvrzeno jako vhodné |
| **Schůzka** | Probíhají jednání |
| **Nabídka** | Nabídka odeslána |
| **Vyjednávání** | Dolaďování podmínek |
| **Uzavřeno vyhráno** | Obchod úspěšný |
| **Uzavřeno prohráno** | Obchod neúspěšný |
<Note>
**5-7 stages is optimal.** Too many stages makes the pipeline hard to scan; too few loses visibility into deal progress.
**57 fází je optimálních.** Příliš mnoho fází ztěžuje rychlé procházení pipeline; příliš málo snižuje přehled o postupu obchodu.
</Note>
## Step 2: Create a Pipeline View
## Krok 2: Vytvořte zobrazení pipeline
1. Go to **Opportunities**
2. Click the view dropdown → **+ Add view**
3. Name it "Sales Pipeline"
4. Click **Create**
5. Open **Options** and select **Kanban** as the layout
1. Přejděte na **Příležitosti**
2. Klikněte na rozbalovací nabídku zobrazení → **+ Přidat zobrazení**
3. Pojmenujte jej "Sales Pipeline"
4. Klikněte na **Vytvořit**
5. Otevřete **Možnosti** a jako rozvržení vyberte **Kanban**
The view automatically uses the Stage field for columns.
Zobrazení automaticky používá pro sloupce pole Stage.
## Step 3: Configure Your View
## Krok 3: Nakonfigurujte své zobrazení
### Show Key Fields
### Zobrazte klíčová pole
1. Click **Options → Fields**
2. Look for fields in the "Hidden Fields" section
3. Click the **eye icon** to display: Company, Amount, Close Date, Owner
1. Klikněte na **Možnosti → Pole**
2. Vyhledejte pole v sekci "Skrytá pole"
3. Klikněte na **ikonu oka** a zobrazte: Společnost, Částka, Datum uzavření, Vlastník
### Enable Aggregations
### Povolte agregace
Show totals at the top of each column:
Zobrazte součty v horní části každého sloupce:
1. Click the number displayed next to a Stage name at the top of a column
2. Select the aggregation type (Count, Sum, Average, etc.)
3. Choose the field to aggregate (e.g., Amount)
1. Klikněte na číslo zobrazené vedle názvu fáze v horní části sloupce
2. Vyberte typ agregace (Počet, Součet, Průměr atd.)
3. Zvolte pole pro agregaci (např. Částka)
**Example:** Show total deal value per stage by aggregating Amount with Sum.
**Příklad:** Zobrazte celkovou hodnotu obchodu podle fází agregováním pole Částka pomocí Součtu.
### Use Compact View (Optional)
### Použijte kompaktní zobrazení (volitelné)
For a high-level overview with minimal card content:
Pro přehled na vysoké úrovni s minimálním obsahem karet:
1. Click **Options**
2. Turn on the toggle for **Compact view**
1. Klikněte na **Možnosti**
2. Zapněte přepínač **Kompaktní zobrazení**
## Step 4: Create Personal and Team Views
## Krok 4: Vytvořte osobní a týmová zobrazení
### "My Pipeline"
### "Moje pipeline"
* **Filter**: Owner = Me
* **Visibility**: Unlisted (personal view)
* **Filtr**: Vlastník =
* **Viditelnost**: Neveřejné (osobní zobrazení)
### "Team Pipeline"
### "Týmová pipeline"
* **Filter**: None (show all)
* **Visibility**: Workspace (shared view)
* **Filtr**: Žádný (zobrazit vše)
* **Viditelnost**: Workspace (sdílené zobrazení)
### "Closing This Month"
### "Uzavření tento měsíc"
* **Type**: Table
* **Filter**: Close Date = This month, Stage ≠ Closed Won, Stage ≠ Closed Lost
* **Sort**: Close Date ascending
* **Typ**: Tabulka
* **Filtr**: Datum uzavření = Tento měsíc, Stage ≠ Closed Won, Stage ≠ Closed Lost
* **Řazení**: Datum uzavření vzestupně
## Working with Opportunities
## Práce s příležitostmi
### Creating Opportunities
### Vytváření příležitostí
* Click **+ New** in the Opportunities view
* Or click **+** in a specific stage column
* Klikněte na **+ New** v zobrazení Příležitostí
* Nebo klikněte na **+** ve sloupci konkrétní fáze
### Moving Through Stages
### Přesun mezi fázemi
Drag and drop opportunity cards between columns to update their stage.
Přetažením karet příležitostí mezi sloupci aktualizujte jejich fázi.
<VimeoEmbed videoId="927888627" title="Video demonstration" />
<VimeoEmbed videoId="927888627" title="Ukázka videa" />
## Osvědčené postupy
### Pipeline Hygiene
### Hygiena pipeline
* Update deals daily as they progress
* Move or close stale deals promptly
* Keep close dates realistic
* Denně aktualizujte obchody podle jejich postupu
* Zastaralé obchody rychle přesouvejte nebo uzavírejte
* Udržujte realistická data uzavření
### Stage Discipline
### Disciplína fází
* Define clear criteria for each stage
* Move deals promptly when criteria are met
* Don't let deals sit in stages too long
* Definujte jasná kritéria pro každou fázi
* Jakmile jsou kritéria splněna, obchody neprodleně přesouvejte
* Nenechávejte obchody ve fázích příliš dlouho
## Related
## Související
* [Kanban Views](/l/cs/user-guide/views-pipelines/capabilities/kanban-views) — aggregations and compact view
* [Filters and Sorting](/l/cs/user-guide/views-pipelines/capabilities/filters-and-sorting) — creating filtered views
* [Kanban zobrazení](/l/cs/user-guide/views-pipelines/capabilities/kanban-views) — agregace a kompaktní zobrazení
* [Filtry a řazení](/l/cs/user-guide/views-pipelines/capabilities/filters-and-sorting) — tvorba filtrovaných zobrazení
@@ -1,90 +1,90 @@
---
title: Use Branches in Workflows
description: Understand how branches work and how to control which path is executed.
title: Používání větví v pracovních postupech
description: Pochopte, jak větve fungují a jak řídit, která cesta se provede.
---
## How Branches Work
## Jak větve fungují
In the workflow editor, you can create multiple paths (branches) going out from a single node. This allows you to build complex automations with different outcomes.
V editoru pracovních postupů můžete vytvářet více cest (větví) vycházejících z jediného uzlu. To vám umožní vytvářet složité automatizace s různými výsledky.
**Important**: When a workflow runs, **all branches execute in parallel by default**. There is no built-in "if/else" logic to choose one branch over another—every path will run simultaneously.
**Důležité**: Když se pracovní postup spustí, **všechny větve se ve výchozím nastavení spouštějí paralelně**. Neexistuje žádná vestavěná "if/else" logika pro výběr jedné větve před jinou—každá cesta poběží současně.
## Controlling Which Branch Runs
## Řízení, která větev se spustí
To execute only one branch based on specific conditions, **add a Filter node at the beginning of each branch**.
Chcete-li provést pouze jednu větev na základě konkrétních podmínek, **přidejte na začátek každé větve uzel Filter**.
### Example Setup
### Ukázkové nastavení
1. Create your workflow with multiple branches from a single node
2. Add a **Filter** node as the first step in each branch
3. Set conditions on each Filter to determine when that branch should continue
4. Only the branch(es) whose Filter conditions are met will proceed
1. Vytvořte pracovní postup s více větvemi z jednoho uzlu
2. Přidejte uzel **Filter** jako první krok v každé větvi
3. Na každém uzlu Filter nastavte podmínky, které určují, kdy má daná větev pokračovat
4. Pokračovat bude pouze větev (případně větve), u níž jsou splněny podmínky uzlu Filter
<img src="/images/user-guide/workflows/branches-with-filters.png" style={{width:'100%'}} />
### How Filters Work
### Jak fungují filtry
* If the Filter condition is **met**: The branch continues executing
* If the Filter condition is **not met**: The branch stops at the Filter node
* Pokud je podmínka Filter **splněna**: Větev pokračuje v provádění
* Pokud podmínka Filter **není splněna**: Větev se zastaví na uzlu Filter
This effectively creates conditional logic where only the appropriate branch runs based on your data.
Tím efektivně vytvoříte podmíněnou logiku, v níž se na základě vašich dat spustí pouze příslušná větev.
## Example: Route by Deal Size
## Příklad: Směrování podle výše obchodu
**Scenario**: When a deal is closed, send different notifications based on deal size.
**Scénář**: Když je obchod uzavřen, odešlete různé oznámení podle výše obchodu.
1. **Trigger**: Opportunity updated (Stage = Closed Won)
2. **Branch 1**: Filter for Amount > $10,000 → Send Slack message to #big-deals
3. **Branch 2**: Filter for Amount$10,000 → Send email to sales manager
1. **Spouštěč**: Příležitost aktualizována (Fáze = Uzavřeno/Vyhráno)
2. **Větev 1**: Filter pro částku > 10 000 $ → Odeslat zprávu na Slack do #big-deals
3. **Větev 2**: Filter pro částku ≤ 10 000 $ → Odeslat e-mail obchodnímu manažerovi
Both branches start, but only the one matching the deal amount will continue past its Filter.
Obě větve se spustí, ale za svým uzlem Filter bude pokračovat pouze ta, která odpovídá částce obchodu.
## Creating Branches
## Vytváření větví
<Note>
To create a new branch from an existing step, click the **+** button on the step and add your action. You can add multiple branches by clicking **+** multiple times.
Chcete-li vytvořit novou větev z existujícího kroku, klikněte na tlačítko **+** u kroku a přidejte svou akci. Více větví můžete přidat opakovaným kliknutím na **+**.
</Note>
1. In the workflow editor, select the step you want to branch from
2. Click the **+** button to add an action
3. This creates one branch
4. Click **+** again on the same step to create additional branches
5. Each branch can have its own sequence of actions
1. V editoru pracovních postupů vyberte krok, ze kterého chcete větvit
2. Klikněte na **+** pro přidání akce
3. Tím vytvoříte jednu větev
4. Pro vytvoření dalších větví klikněte znovu na **+** u stejného kroku
5. Každá větev může mít vlastní posloupnost akcí
## Merging Branches Back Together
## Sloučení větví zpět do jedné
After parallel branches complete their work, you can merge them back into a single path:
Po dokončení práce paralelních větví je můžete sloučit zpět do jedné cesty:
1. Complete your branched actions
2. Add a new step that should run after all branches
3. Drag a connection from the last step of each branch to this new step
4. The merged step waits for all connected branches to complete before executing
1. Dokončete akce ve větvích
2. Přidejte nový krok, který se má spustit po všech větvích
3. Přetáhněte spojení z posledního kroku každé větve do tohoto nového kroku
4. Sloučený krok před spuštěním počká na dokončení všech připojených větví
### Example: Process Then Notify
### Příklad: Zpracovat a poté upozornit
```
Trigger
Spouštěč
├── Branch A: Update Customer Record
├── Větev A: Aktualizovat záznam zákazníka
└── Branch B: Create Support Ticket
└── Větev B: Vytvořit tiket podpory
↘ ↙
Merged Step: Send Confirmation Email
Sloučený krok: Odeslat potvrzovací e-mail
```
The confirmation email sends only after both the customer update and ticket creation are done.
Potvrzovací e-mail se odešle až po dokončení aktualizace zákazníka i vytvoření tiketu.
## Osvědčené postupy
* Always use **Filter nodes** at the start of branches when you want conditional execution
* Keep branch conditions **mutually exclusive** to avoid duplicate actions
* Test your workflows with different data to ensure the correct branches run
* **Rename branch steps** descriptively so it's clear what each path does
* **Merge branches** when you need a final action after parallel processing
* Na začátku větví vždy používejte **uzly Filter**, když chcete podmíněné spouštění
* Podmínky větví udržujte **vzájemně se vylučující**, abyste předešli duplicitním akcím
* Testujte své pracovní postupy s různými daty, abyste měli jistotu, že se spouštějí správné větve
* **Přejmenujte kroky ve větvích** popisně, aby bylo jasné, co která cesta dělá
* **Sloučte větve**, když po paralelním zpracování potřebujete závěrečnou akci
## Related
## Související
* [Workflows FAQ](/l/cs/user-guide/workflows/how-tos/need-more-help/workflows-faq) — answers about parallel execution
* [Workflow Actions](/l/cs/user-guide/workflows/capabilities/workflow-actions) — available actions for branches
* [Často kladené dotazy k pracovním postupům](/l/cs/user-guide/workflows/how-tos/need-more-help/workflows-faq) — odpovědi týkající se paralelního provádění
* [Akce pracovních postupů](/l/cs/user-guide/workflows/capabilities/workflow-actions) — dostupné akce pro větve
@@ -6,10 +6,6 @@ image: /images/user-guide/workflows/workflow.png
Iterator lets you loop through an array of records and perform actions on each one. It's essential for workflows that need to process multiple records returned by Search Records or received via webhooks.
<Note>
Iterator is currently in beta. Activate it under **Settings → Releases → Lab**.
</Note>
## When to Use Iterator
| Scenario | Příklad |
@@ -96,216 +96,216 @@ Vytvoří nový záznam nebo aktualizuje existující na základě kritérií sh
* Použijte data z předchozích kroků k vyplnění polí
**How it works**:
**Jak to funguje**:
1. Searches for a record matching your criteria
2. If found → updates the existing record
3. If not found → creates a new record
1. Vyhledá záznam odpovídající vašim kritériím
2. Pokud nalezeno → aktualizuje existující záznam
3. Pokud nenalezeno → vytvoří nový záznam
**Output**: The created or updated record data is available for use in subsequent steps.
**Výstup**: Data vytvořeného nebo aktualizovaného záznamu jsou k dispozici pro použití v následujících krocích.
## Flow Actions
## Akce toku
### Iterátor
**Loops through an array of records** returned from a previous step, allowing you to perform actions on each record individually.
**Prochází polem záznamů** vrácených z předchozího kroku, což umožňuje provádět akce na každém záznamu jednotlivě.
**Konfigurace**:
* Select the array of records from a previous step (e.g., results from Search Records, from a Manual trigger with Bulk availability, from a code node)
* Vyberte pole záznamů z předchozího kroku (např. výsledky z vyhledávání záznamů, z ručního spouštěče s hromadnou dostupností, z uzlu kódu)
* Definujte akce, které budou provedeny na každém záznamu v cyklu.
<Note>
- You can add several actions within an iterator.
- When using branches inside an iterator, make sure the last step of each branch connects back to the iterator to close the loop.
- V rámci iterátoru můžete přidat několik akcí.
- Při používání větví uvnitř iterátoru se ujistěte, že poslední krok každé větve se vrací zpět do iterátoru, aby se smyčka uzavřela.
</Note>
* Access `Current Item` Fields: to use fields from the record currently being processed, click on the **Iterator** step, then select **Current item**. The list of available fields from that record will be displayed and can be selected for use in subsequent actions.
* Přístup k polím `Current Item`: chcete-li použít pole ze záznamu, který se právě zpracovává, klikněte na krok **Iterator** a vyberte **Current item**. Zobrazí se seznam dostupných polí z daného záznamu a můžete je vybrat k použití v následujících akcích.
<VimeoEmbed videoId="1146577247" title="Video demonstration" />
<VimeoEmbed videoId="1146577247" title="Ukázka videa" />
### Filtr
Filters records based on specified conditions, allowing only records that meet the criteria to pass through.
Filtruje záznamy na základě zadaných podmínek a propustí pouze záznamy, které splňují kritéria.
**Konfigurace**:
* Select the record to filter
* Vyberte záznam k filtrování
* Definujte filtrační podmínky a kritéria
* Nakonfigurujte, které záznamy by měly projít do následujících kroků
<Note>
1. **Output**: Filter nodes don't return data—they act as gates. If the conditions are met, the workflow continues. If not, the workflow stops at that branch.
2. The `IS` operator can be used with numeric fields. It performs as an `EQUAL`.
1. **Výstup**: Uzly filtru nevracejí data — fungují jako brány. Pokud jsou podmínky splněny, pracovní postup pokračuje. Pokud ne, pracovní postup se v dané větvi zastaví.
2. Operátor `IS` lze použít s číselnými poli. Chová se jako `EQUAL`.
</Note>
### Delay
### Zpoždění
Pauses workflow execution for a specified duration or until a specific date/time.
Pozastaví provádění pracovního postupu na zadanou dobu nebo do konkrétního data/času.
**Delay Types**:
**Typy zpoždění**:
| Typ | Popis |
| ------------------ | ------------------------------------------------------------------ |
| **Duration** | Wait for a specific amount of time (days, hours, minutes, seconds) |
| **Scheduled Date** | Wait until a specific date and time |
| Typ | Popis |
| --------------------- | ------------------------------------------------------ |
| **Doba trvání** | Čekat po konkrétní dobu (dny, hodiny, minuty, sekundy) |
| **Naplánované datum** | Čekat do konkrétního data a času |
**Configuration for Duration**:
**Konfigurace pro dobu trvání**:
* Set days, hours, minutes, and/or seconds
* Combine multiple units (e.g., 2 days and 4 hours)
* Nastavte dny, hodiny, minuty a/nebo sekundy
* Kombinujte více jednotek (např. 2 dny a 4 hodiny)
**Configuration for Scheduled Date**:
**Konfigurace pro naplánované datum**:
* Select a date and time
* Can reference a date field from a previous step (e.g., follow up 3 days after a meeting)
* Vyberte datum a čas
* Může odkazovat na datumové pole z předchozího kroku (např. navázání kontaktu 3 dny po schůzce)
**Případy použití**:
* Wait 24 hours before sending a follow-up email
* Pause until an opportunity's close date
* Schedule actions for business hours
* Počkejte 24 hodin před odesláním navazujícího e-mailu
* Pozastavte až do data uzavření příležitosti
* Naplánujte akce na pracovní hodiny
<Note>
The scheduled date cannot be in the past. If a date field from a previous step is used and the date has already passed, the workflow will fail.
Naplánované datum nesmí být v minulosti. Pokud je použito datumové pole z předchozího kroku a datum již uplynulo, pracovní postup selže.
</Note>
**Limits & Credits**:
**Limity a kredity**:
* **No maximum duration limit**—you can set delays of minutes, days, weeks, or longer
* **1 credit consumed** when the Delay node executes, regardless of duration
* **No credits consumed** while waiting—a 5-minute delay costs the same as a 5-day delay
* **Žádný maximální limit délky** — můžete nastavit zpoždění v minutách, dnech, týdnech nebo i delší období
* **Spotřebován 1 kredit** při spuštění uzlu Zpoždění, bez ohledu na délku
* **Žádné kredity se nespotřebovávají** během čekání — 5minutové zpoždění stojí stejně jako 5denní zpoždění
## Communication Actions
## Komunikační akce
### Odeslat e-mail
Odesílá e-mail z vašeho pracovního postupu. This is great for templated group emails. Emails will look like the ones you send from your mailbox.
Not suited for newsletters (which require richer formatting) or automated email sequences.
Odesílá e-mail z vašeho pracovního postupu. Skvělé pro šablonované hromadné e-maily. E-maily budou vypadat jako ty, které posíláte ze své schránky.
Nevhodné pro newslettery (které vyžadují bohatší formátování) ani pro automatizované e-mailové sekvence.
**Prerequisites**: Add an email account in Settings → Accounts
**Předpoklady**: Přidejte e-mailový účet v Nastavení → Účty
**Konfigurace**:
* Select the sender email account
* Vyberte e-mailový účet odesílatele
<Note>
You can only send emails from mailboxes synced to your own Twenty account. Sending from other team members' mailboxes (e.g., the account owner's email) is on the roadmap.
E-maily můžete odesílat pouze z poštovních schránek synchronizovaných s vaším vlastním účtem Twenty. Odesílání z poštovních schránek ostatních členů týmu (např. e-mail vlastníka účtu) je v plánu.
</Note>
For all the following steps, you can reference variables from previous steps for personalization.
Ve všech následujících krocích můžete pro personalizaci odkazovat na proměnné z předchozích kroků.
* Zadejte e-mailovou adresu příjemce.
<Note>
Only one recipient is possible at the moment.
V tuto chvíli je možný pouze jeden příjemce.
</Note>
* Nastavte předmět.
* Sestavte tělo zprávy. You can format links, create numbered list, bullet point lists, add attachments.
* Sestavte tělo zprávy. Můžete formátovat odkazy, vytvářet číslované i odrážkové seznamy, přidávat přílohy.
<Note>
Adding HTML signatures is not possible at the moment.
Přidávání HTML podpisů momentálně není možné.
</Note>
### Formulář
Vyvolá formulář během provádění pracovního postupu pro sběr uživatelských vstupů. The responses can then be used in subsequent steps to create records, send emails, or execute any other action based on the input.
Vyvolá formulář během provádění pracovního postupu pro sběr uživatelských vstupů. Odpovědi lze poté použít v následujících krocích k vytváření záznamů, odesílání e-mailů nebo provádění jiných akcí na základě zadaných údajů.
<Warning>
**Forms are designed for manual triggers only**. U workflow s jinými spouštěči (vytvoření záznamu, aktualizace atd.) jsou formuláře přístupné pouze přes rozhraní běžů workflow, což neodpovídá očekávané uživatelské zkušenosti. V roce 2026 bude uvedeno centrum oznámení pro správnou podporu formulářů v automatizovaných pracovních postupech.
**Formuláře jsou navrženy pouze pro ruční spuštění**. U workflow s jinými spouštěči (vytvoření záznamu, aktualizace atd.) jsou formuláře přístupné pouze přes rozhraní běžů workflow, což neodpovídá očekávané uživatelské zkušenosti. V roce 2026 bude uvedeno centrum oznámení pro správnou podporu formulářů v automatizovaných pracovních postupech.
</Warning>
**Konfigurace**:
* Configure the fields that users will be asked to fill. For each field, choose
* a type among text, number, date, a given record, a select field. Select fields from all objects are available.
* a label
* a default value under `Placeholder` (optional)
* Edit the form title
* Nakonfigurujte pole, která budou uživatelé vyplňovat. Pro každé pole zvolte
* typ z možností: text, číslo, datum, daný záznam, výběrové pole. Výběrová pole ze všech objektů jsou k dispozici.
* štítek
* výchozí hodnotu pod `Placeholder` (volitelné)
* Upravte název formuláře
**Výstup**: Odpovědi z formuláře jsou k dispozici pro použití v následujících krocích.
**Example**: The "Quick Lead" workflow is available by default in all workspaces, available anywhere in the Command Menu `Cmd + K`.
**Příklad**: Pracovní postup "Quick Lead" je ve výchozím nastavení dostupný ve všech pracovních prostorech a je dostupný odkudkoli v nabídce Command `Cmd + K`.
**How to fill the form**:
**Jak vyplnit formulář**:
* Trigger your manual workflow from the command menu `Cmd K`
* Fill the form that is displayed in the side panel and click `Submit`.
* Spusťte svůj ruční pracovní postup z příkazové nabídky `Cmd K`
* Vyplňte formulář zobrazený v postranním panelu a klikněte na `Submit`.
<Note>
The fields cannot be made mandatory.
Pole nelze nastavit jako povinná.
</Note>
<VimeoEmbed videoId="1147277989" title="Video demonstration" />
<VimeoEmbed videoId="1147277989" title="Ukázka videa" />
## Integration Actions
## Integrační akce
### Kód
Runs custom JavaScript within your workflow.
Spouští vlastní JavaScript ve vašem pracovním postupu.
**Konfigurace**:
* Přístup k proměnným z předchozích kroků. You can edit the variables names dynamically.
* Přístup k proměnným z předchozích kroků. Názvy proměnných můžete upravovat dynamicky.
<VimeoEmbed videoId="1147281795" title="Video demonstration" />
<VimeoEmbed videoId="1147281795" title="Ukázka videa" />
* Zapište JavaScriptový kód v editoru
* Vrátit proměnné pro použití v následujících krocích
* Testovat kód přímo ve kroku
<Note>
If you need to use external API keys in your code, you must input them directly in the function body. You cannot configure API keys elsewhere and reference them in the serverless function.
Pokud potřebujete ve svém kódu použít externí klíče API, musíte je zadat přímo do těla funkce. Klíče API nelze nakonfigurovat jinde a odkazovat na ně v bezserverové funkci.
</Note>
<Tip>
**Working with arrays?** Arrays from external systems or previous steps may come as strings. See [How to handle arrays in Code actions](/l/cs/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions) for the solution.
**Pracujete s poli?** Pole z externích systémů nebo předchozích kroků mohou přijít jako řetězce. Řešení viz [Jak pracovat s poli v akcích Code](/l/cs/user-guide/workflows/how-tos/advanced-configurations/handle-arrays-in-code-actions).
</Tip>
<Tip>
Click the square icon at the top right of the code editor to display it in full screen — helpful since the default editor width is limited.
Klikněte na čtvercovou ikonu vpravo nahoře v editoru kódu a zobrazte jej na celou obrazovku — hodí se to, protože výchozí šířka editoru je omezená.
</Tip>
### HTTP požadavek
Sends a request to an external API as part of your workflow.
Odešle požadavek na externí API v rámci vašeho pracovního postupu.
<img src="/images/user-guide/workflows/http_action.png" style={{width:'100%'}} />
**Konfigurace**:
* Zadejte URL endpointu API. Using parameters from previous steps is possible.
* Zadejte URL endpointu API. Je možné použít parametry z předchozích kroků.
* Vyberte metodu HTTP (GET, POST, PUT, PATCH, DELETE)
* Přidejte potřebné hlavičky a hodnoty
* Poskytněte ukázku odpovědi pro zobrazení struktury
## AI Actions
## Akce AI
### AI Agent - Coming Soon
### Agent AI již brzy
Runs an AI agent within your workflow to perform intelligent tasks.
Spouští agenta AI ve vašem pracovním postupu k provádění inteligentních úloh.
**Konfigurace**:
* **Agent**: Select an existing AI agent or use the default agent
* **Prompt**: Write the instruction for the AI agent
* Reference variables from previous steps in the prompt
* **Agent**: Vyberte existujícího agenta AI nebo použijte výchozího agenta
* **Prompt**: Napište instrukci pro agenta AI
* Odkazujte v promptu na proměnné z předchozích kroků
**What AI Agents can do**:
**Co agenti AI dokážou**:
* Analyze and summarize data
* Classify or categorize records
* Generate text content
* Make decisions based on data
* Interact with your CRM data using tools
* Analyzovat a shrnovat data
* Klasifikovat nebo kategorizovat záznamy
* Generovat textový obsah
* Rozhodovat se na základě dat
* Pracovat s vašimi daty CRM pomocí nástrojů
**Output**: The AI agent's response is available for use in subsequent steps. If the agent has a structured output schema, the response will follow that format.
**Výstup**: Odpověď agenta AI je k dispozici pro použití v následujících krocích. Pokud má agent strukturované schéma výstupu, bude odpověď tento formát dodržovat.
<Note>
AI Agent actions consume workflow credits based on the AI model used. See [Workflow Credits](/l/cs/user-guide/workflows/capabilities/workflow-credits) for details.
Akce agenta AI spotřebovávají kredity pracovního postupu podle použitého modelu AI. Podrobnosti viz [Kredity pracovního postupu](/l/cs/user-guide/workflows/capabilities/workflow-credits).
</Note>
<Note>
AI agents respect role-based permissions. You can assign specific roles to agents under **Settings → Roles** to control what data they can access. See [Permissions](/l/cs/user-guide/permissions-access/capabilities/permissions) for details.
Agenti AI respektují oprávnění založená na rolích. V části **Nastavení → Role** můžete agentům přiřadit konkrétní role, abyste řídili, k jakým datům mají přístup. Podrobnosti viz [Oprávnění](/l/cs/user-guide/permissions-access/capabilities/permissions).
</Note>
@@ -1,23 +1,23 @@
---
title: Spouštěče pracovních postupů
description: Learn about the different triggers that start your workflows.
description: Seznamte se s různými spouštěči, které zahajují vaše pracovní postupy.
---
## About Triggers
## O spouštěčích
Pracovní postupy vždy začínají jedním spouštěčem, který určuje, kdy by měla být automatizace spuštěna.
<img src="/images/user-guide/workflows/workflow_triggers.png" style={{width:'100%'}} />
<Tip>
**Advanced objects are supported!** Beyond standard CRM objects (People, Companies, Opportunities), you can also trigger workflows and perform actions on:
**Pokročilé objekty jsou podporovány!** Kromě standardních CRM objektů (Lidé, Společnosti, Příležitosti) můžete také spouštět pracovní postupy a provádět akce nad:
* Členové pracovního prostoru
* Calendar Events
* Messages (Emails)
* Tasks, Notes, and many other system objects
* Události v kalendáři
* Zprávy (e-maily)
* Úkoly, poznámky a mnoho dalších systémových objektů
This opens up powerful automations like notifying team members when calendar events are created, or processing incoming emails automatically.
To umožňuje výkonné automatizace, například upozorňovat členy týmu, když jsou v kalendáři vytvořeny události, nebo automaticky zpracovávat příchozí e-maily.
</Tip>
## Záznam je vytvořen
@@ -27,9 +27,9 @@ Spouští pracovní postup, když je vytvořen nový záznam ve vybraném objekt
**Konfigurace**: Vyberte typ objektu, který chcete sledovat ohledně nových záznamů.
<Note>
* This trigger is great for records created by csv, mailbox and calendar synchronization, API.
* **It is not recommended for records created manually**: with this trigger, workflows start as soon as the record is created. Since Twenty UI offers auto-save on the fly (there is not an edit mode and then a validation to save records), the workflow will be triggered before the user inputs all the fields.
To trigger this workflow on records created manually, it is recommended to use the trigger `Record is created or updated` instead.
* Tento spouštěč je skvělý pro záznamy vytvořené pomocí CSV, synchronizace poštovní schránky a kalendáře nebo API.
* **Nedoporučuje se pro záznamy vytvářené ručně**: s tímto spouštěčem se pracovní postupy spouštějí okamžitě po vytvoření záznamu. Protože Twenty UI nabízí průběžné automatické ukládání (neexistuje režim úprav a následné potvrzení pro uložení záznamů), pracovní postup bude spuštěn dříve, než uživatel vyplní všechna pole.
Chcete-li tento pracovní postup spouštět u záznamů vytvořených ručně, doporučujeme místo toho použít spouštěč `Record is created or updated`.
</Note>
## Záznam je aktualizován
@@ -62,43 +62,43 @@ Spouští pracovní postup, když je záznam odstraněn z objektu.
**Konfigurace**: Vyberte typ objektu, který chcete sledovat ohledně odstranění.
## Manual Trigger
## Ruční spouštěč
Spustí pracovní postup, když jej vyvolá uživatelská akce. This trigger can be accessed through the `Cmd+K` menu or via a custom button that will be displayed in the top navbar after selecting record(s).
Spustí pracovní postup, když jej vyvolá uživatelská akce. K tomuto spouštěči je možné přistupovat prostřednictvím nabídky `Cmd+K` nebo pomocí vlastního tlačítka, které se zobrazí v horní navigační liště po výběru záznamu nebo záznamů.
<img src="/images/user-guide/workflows/add_to_newsletter_button.png" style={{width:'100%'}} />
**Konfigurace dostupnosti**:
Vyberte, jak má pracovní postup zpracovávat výběr záznamů:
* **Global**: No record is required to trigger this workflow. The workflow is triggered from the command menu `Cmd + K` anywhere (from any object) and does not use record(s) as input.
* **Globální**: K aktivaci tohoto pracovního postupu není vyžadován žádný záznam. Pracovní postup se spouští z příkazové nabídky `Cmd + K` odkudkoli (z jakéhokoli objektu) a nepoužívá jako vstup žádné záznamy.
* **Single**: The selected record(s) will be passed to your workflow. Toto je nastaveno pro daný objekt. Před spuštěním pracovního postupu je možné vybrat několik záznamů. The workflow will run from beginning to end as many times as there are records selected.
* **Jednotlivé**: Vybraný záznam či záznamy budou předány vašemu pracovnímu postupu. Toto je nastaveno pro daný objekt. Před spuštěním pracovního postupu je možné vybrat několik záznamů. Pracovní postup se spustí od začátku do konce tolikrát, kolik je vybraných záznamů.
<Note>
**Soft limit: 100 runs/minute**. Beyond this, workflows remain in "Not Started" status and are processed gradually—either by a background job or when another workflow enters the queue. This means you can select more than 100 records with a Single trigger; execution will just be slower.
**Měkký limit: 100 běhů za minutu**. Po překročení tohoto limitu zůstanou pracovní postupy ve stavu "Not Started" a budou zpracovávány postupně—buď úlohou na pozadí, nebo když do fronty vstoupí další pracovní postup. To znamená, že se spouštěčem Jednotlivé můžete vybrat více než 100 záznamů; provádění bude jen pomalejší.
</Note>
* **Hromadné**: Vybrané záznamy budou předány do vašeho pracovního postupu. Toto je nastaveno pro daný objekt. Před spuštěním pracovního postupu je možné vybrat několik záznamů. Pracovní postup poběží jednou, přičemž celý seznam záznamů bude použit jako vstup. This means the workflow needs to contain an [Iterator action](/l/cs/user-guide/workflows/capabilities/workflow-actions#iterator).
* **Hromadné**: Vybrané záznamy budou předány do vašeho pracovního postupu. Toto je nastaveno pro daný objekt. Před spuštěním pracovního postupu je možné vybrat několik záznamů. Pracovní postup poběží jednou, přičemž celý seznam záznamů bude použit jako vstup. To znamená, že pracovní postup musí obsahovat [akci Iterator](/l/cs/user-guide/workflows/capabilities/workflow-actions#iterator).
<Note>
This is more advanced, and best for people who want to optimize the number of workflow runs.
Toto je pokročilejší a hodí se pro uživatele, kteří chtějí optimalizovat počet běhů pracovního postupu.
</Note>
<img src="/images/user-guide/workflows/manual_trigger.png" style={{width:'100%'}} />
**Additional Configuration**:
**Dodatečné nastavení**:
* Select the target object (for Single and Bulk availability)
* Vyberte cílový objekt (pro dostupnost v režimu Jednotlivé a Hromadné)
* Vyberte ikonu příkazu pro spuštění pracovního postupu
* Nakonfigurujte umístění v navigaci (připnuté nebo nepřipnuté)
**Způsoby přístupu**:
* `Cmd+K` menu to find and launch manual workflows
* Nabídka `Cmd+K` pro vyhledání a spuštění ručních pracovních postupů
* Vlastní tlačítko v horní navigaci (pokud je nastaveno)
## Time-Based Trigger: On a Schedule
## Časový spouštěč: Podle plánu
Spouští pracovní postup v opakovaných intervalech, které definujete.
@@ -108,29 +108,29 @@ Spouští pracovní postup v opakovaných intervalech, které definujete.
* Zadejte hodnotu nebo použijte vlastní cron výrazy pro rozšířené plánování
<Note>
**Timezone**: Scheduled workflows run in **UTC**. When setting hours for daily schedules, convert your local time to UTC.
**Časové pásmo**: Plánované pracovní postupy běží v **UTC**. Při nastavování hodin pro denní plány převeďte svůj místní čas na UTC.
</Note>
## External Trigger: Webhook
## Externí spouštěč: Webhook
Starts the workflow when a GET or POST request is received from an external service.
Spustí pracovní postup, když je z externí služby přijat požadavek typu GET nebo POST.
<img src="/images/user-guide/workflows/webhook_trigger.png" style={{width:'100%'}} />
**Konfigurace**:
* The workflow provides a unique webhook URL—copy this and add it to your external system as the endpoint to call.
* For POST requests, define the expected body structure so Twenty knows what data to expect. Add here the fields you will receive that will be needed below in your workflow.
* Configure authentication (coming soon).
* Pracovní postup poskytne jedinečnou URL adresu webhooku—zkopírujte ji a přidejte do svého externího systému jako koncový bod, který se má volat.
* Pro požadavky POST definujte očekávanou strukturu těla, aby Twenty vědělo, jaká data očekávat. Zde přidejte pole, která obdržíte a která budou dále ve vašem pracovním postupu potřeba.
* Nakonfigurujte ověřování (již brzy).
## Choosing the Right Trigger
## Výběr správného spouštěče
| Use Case | Recommended Trigger |
| --------------------------- | ------------------------------------ |
| New leads need processing | Záznam je vytvořen |
| Data changes need sync | Záznam je aktualizován |
| Import/manual data handling | Záznam je aktualizován nebo vytvořen |
| Cleanup after deletion | Záznam je odstraněn |
| User-initiated action | Spustit manuálně |
| Recurring reports | On a Schedule |
| External integration | Webhook or On a Schedule |
| Případ použití | Doporučený spouštěč |
| ---------------------------------------------- | ------------------------------------ |
| Nové potenciální kontakty je potřeba zpracovat | Záznam je vytvořen |
| Změny dat je potřeba synchronizovat | Záznam je aktualizován |
| Import/ruční zpracování dat | Záznam je aktualizován nebo vytvořen |
| Čištění po smazání | Záznam je odstraněn |
| Akce spuštěná uživatelem | Spustit manuálně |
| Pravidelné reporty | Podle plánu |
| Externí integrace | Webhook nebo Podle plánu |
@@ -1,56 +1,56 @@
---
title: Detect Stale Opportunities
description: Automatically notify managers when opportunities haven't been updated.
title: Odhalte zastaralé příležitosti
description: Automaticky upozorňujte manažery, když příležitosti nebyly aktualizovány.
---
Keep your pipeline healthy by alerting managers when opportunities go stale. This workflow checks for opportunities that haven't been updated in a specified number of days.
Udržujte svou obchodní pipeline zdravou tím, že budete upozorňovat manažery, když příležitosti zastarávají. Tento pracovní postup kontroluje příležitosti, které nebyly aktualizovány po zadaný počet dní.
## The Problem
## Problém
Opportunities sitting without updates lead to:
Příležitosti bez aktualizací vedou k:
* Deals going cold
* Unreliable forecasts
* Lost revenue
* Obchody chladnou
* Nespolehlivé prognózy
* Ztracené tržby
## The Solution
## Řešení
Create a scheduled workflow that finds stale opportunities and emails their managers.
Vytvořte plánovaný pracovní postup, který najde zastaralé příležitosti a odešle e-mail jejich manažerům.
## Step-by-Step Setup
## Nastavení krok za krokem
### Step 1: Create the Workflow
### Krok 1: Vytvořte pracovní postup
1. Go to **Settings → Workflows**
2. Click **+ New Workflow**
3. Name it "Stale Opportunity Alert"
1. Přejděte na **Nastavení → Pracovní postupy**
2. Klikněte na **+ Nový pracovní postup**
3. Pojmenujte jej "Upozornění na zastaralé příležitosti"
### Step 2: Configure the Trigger
### Krok 2: Nakonfigurujte spouštěč
1. Select **On a Schedule**
2. Set to run daily (e.g., every day at 8 AM)
1. Vyberte **Podle plánu**
2. Nastavte spouštění denně (např. každý den v 8:00)
### Step 3: Search for Stale Opportunities
### Krok 3: Vyhledejte zastaralé příležitosti
1. Add **Search Records** action
1. Přidejte akci **Vyhledat záznamy**
2. Nakonfigurujte:
| Pole | Hodnota |
| ---------- | ----------------------------------------------- |
| **Object** | Příležitosti |
| **Filter** | Updated At is before (today - 7 days) |
| **Filter** | Stage is not "Closed Won" AND not "Closed Lost" |
| **Limit** | 100 |
| Pole | Hodnota |
| ---------- | --------------------------------------------- |
| **Objekt** | Příležitosti |
| **Filtr** | Datum aktualizace je dříve než (dnes - 7 dní) |
| **Filtr** | Fáze není "Closed Won" a není "Closed Lost" |
| **Limit** | 100 |
### Step 4: Check If Any Found
### Krok 4: Zkontrolujte, zda se něco našlo
1. Add **Filter** action
2. Condition: `{{searchRecords.length}}` is greater than 0
3. If no stale opportunities, the workflow stops here
1. Přidejte akci **Filtr**
2. Podmínka: `{{searchRecords.length}}` je větší než 0
3. Pokud nejsou žádné zastaralé příležitosti, pracovní postup se zde zastaví
### Step 5: Format the Alert (Code Action)
### Krok 5: Naformátujte upozornění (akce Code)
Add a **Code** action to format the email:
Přidejte akci **Code** pro formátování e-mailu:
```javascript
export const main = async (params) => {
@@ -88,49 +88,49 @@ export const main = async (params) => {
};
```
### Step 6: Send Alert Email
### Krok 6: Odešlete upozornění e-mailem
Add **Send Email** action:
Přidejte akci **Odeslat e-mail**:
| Pole | Hodnota |
| ----------- | ----------------------------------------------------------- |
| **To** | sales-manager@yourcompany.com |
| **Subject** | `🚨 {{code.totalCount}} Stale Opportunities Need Attention` |
| **Body** | `{{code.summary}}` |
| Pole | Hodnota |
| --------------- | -------------------------------------------------------------------- |
| **Komu** | sales-manager@yourcompany.com |
| **Předmět** | `🚨 {{code.totalCount}} zastaralých příležitostí vyžaduje pozornost` |
| **Text zprávy** | `{{code.summary}}` |
### Step 7: Test and Activate
### Krok 7: Otestujte a aktivujte
1. Click **Test** to run the workflow
2. Check that the email contains the right data
3. Activate when ready
1. Klikněte na **Test** a spusťte pracovní postup
2. Zkontrolujte, že e-mail obsahuje správné údaje
3. Až budete připraveni, aktivujte
## Customization Options
## Možnosti přizpůsobení
### Change Staleness Threshold
### Změňte hranici zastarání
Modify the Search Records filter to change from 7 days to your preferred period:
Upravte filtr akce Vyhledat záznamy a změňte ze 7 dnů na vámi preferované období:
* 3 days for high-velocity sales
* 14 days for enterprise deals
* 30 days for long sales cycles
* 3 dny pro rychlé prodeje
* 14 dní pro podnikové obchody
* 30 dní pro dlouhé prodejní cykly
### Alert Individual Reps
### Upozorněte jednotlivé obchodní zástupce
Instead of one manager email, use **Iterator** to send personalized emails to each rep about their own stale deals.
Místo jednoho e-mailu manažerovi použijte **Iterator** k odeslání personalizovaných e-mailů každému zástupci o jeho vlastních zastaralých obchodech.
### Add Escalation
### Přidejte eskalaci
Create multiple workflows with increasing severity:
Vytvořte více pracovních postupů se zvyšující se závažností:
1. Day 7: Email to rep
2. Day 14: Email to rep + manager
3. Day 21: Create task for manager to intervene
1. Den 7: E-mail zástupci
2. Den 14: E-mail zástupci + manažerovi
3. Den 21: Vytvořte úkol pro manažera k zásahu
### Include in Slack
### Zahrňte do Slacku
Use **HTTP Request** to post to a Slack webhook instead of or in addition to email.
Použijte **HTTP Request** k odeslání na webhook ve Slacku místo e-mailu nebo navíc k e-mailu.
## Related
## Související
* [Workflow Actions](/l/cs/user-guide/workflows/capabilities/workflow-actions)
* [Send Emails from Workflows](/l/cs/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Akce pracovních postupů](/l/cs/user-guide/workflows/capabilities/workflow-actions)
* [Odesílání e-mailů z pracovních postupů](/l/cs/user-guide/workflows/capabilities/send-emails-from-workflows)
@@ -0,0 +1,127 @@
---
title: Notify Teammates of a Note to Review
description: Send automatic email notifications when assigning a colleague to review a note.
---
import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
<Note>
**Tagging teammates directly in notes is not yet supported.** This feature is planned for the second half of 2026. In the meantime, this workflow provides a practical workaround.
</Note>
## The Challenge
You want to tag a colleague in a note so they receive a notification to review it. Today, Twenty doesn't support @mentions in notes or tasks.
## The Workaround
Instead of tagging in the note text, you can:
1. Create a **Reviewer** relation field on the Notes object
2. Assign the reviewer when creating or editing the note
3. A workflow automatically sends an email to the reviewer with a link to the note
<Warning>
**Limitation**: This approach allows assigning one reviewer per field. If you need to notify multiple people, create additional relation fields (e.g., Reviewer 1, Reviewer 2). This won't scale well if you need to tag many collaborators at once.
</Warning>
## Nastavení krok za krokem
### Step 1: Create the Reviewer Field
<img src="/images/user-guide/workflows/reviewer-field-for-note.png" style={{width:'100%'}} />
1. Go to **Settings → Data Model → Notes**
2. Click **Add Field**
3. Nakonfigurujte:
| Nastavení | Hodnota |
| ------------------ | --------------------------------- |
| **Name** | Reviewer |
| **Typ** | Vztah |
| **Related Object** | Člen pracovního prostoru |
| **Relation Type** | Many Notes → One Workspace Member |
4. Save the field
### Krok 2: Vytvořte pracovní postup
<VimeoEmbed videoId="1151897168" title="Ukázka videa" />
#### Create the Workflow Trigger
1. Go to the main view and create a new workflow
2. Select **Record Updated** as the trigger
3. Choose **Note** as the object and specify the Reviewer field.
4. This will trigger whenever the reviewer of a note is updated.
#### Add a Filter to Check Reviewer Was Just Assigned
Add a **Filter** action to ensure the workflow only continues when a reviewer is assigned:
| Condition | Hodnota |
| ------------ | ------------ |
| **Reviewer** | není prázdné |
#### Search for the Workspace Member
1. Add a **Search Records** action
2. Select **Workspace Member** (under Advanced Objects)
3. Add a filter:
| Condition | Hodnota |
| --------- | ---------------------------- |
| **ID** | equals `{{note.reviewerId}}` |
This retrieves the full workspace member record, including their email address and name.
#### Send the Notification Email
1. Add a **Send Email** action
2. Nakonfigurujte:
| Pole | Hodnota |
| --------------- | --------------------------------------------------- |
| **Komu** | Search Record → First Workspace Member → User Email |
| **Předmět** | A note needs your review |
| **Text zprávy** | See example below |
**Email body example:**
```text
Hi {{searchRecord.firstWorkspaceMember.name.firstName}},
You've been assigned to review a note.
View the note here:
https://yourSubDomain.twenty.com/object/note/{{recordIsUpdated.id}}
Best,
Twenty
```
<Note>
Replace `yourSubDomain` with your actual Twenty workspace subdomain.
</Note>
#### Test and Activate
1. Click **Test** to run the workflow manually
2. Create or edit a note and assign a reviewer
3. Check the reviewer's inbox for the notification email
4. Activate the workflow
## Použití
Once set up, your team can use this workflow by:
1. Creating a new note (or editing an existing one)
2. Selecting a colleague in the **Reviewer** field
3. The colleague automatically receives an email with a direct link to the note
## Související
* [Spouštěče pracovních postupů](/l/cs/user-guide/workflows/capabilities/workflow-triggers)
* [Send Emails from Workflows](/l/cs/user-guide/workflows/capabilities/send-emails-from-workflows)
* [Create Custom Fields](/l/cs/user-guide/data-model/how-tos/create-custom-fields)
* [Create Relation Fields](/l/cs/user-guide/data-model/how-tos/create-relation-fields)
@@ -1,170 +1,170 @@
---
title: Řešení problémů s workflow
description: Common workflow issues and how to resolve them.
description: Běžné problémy s pracovními postupy a jak je vyřešit.
---
## Běžné problémy a řešení
### Workflow se nespouští
**Symptoms**: Your workflow doesn't run when you expect it to.
**Příznaky**: Váš pracovní postup se nespustí, když to očekáváte.
**Possible Causes**:
**Možné příčiny**:
1. **Workflow not activated**: Ensure the workflow is set to "Active" not "Draft"
2. **Trigger conditions not met**: Verify the trigger matches your expected event
3. **Field not monitored**: For "Record is Updated" triggers, ensure the specific field is being watched
4. **Permissions**: Check you have permission to run workflows
1. **Pracovní postup není aktivován**: Ujistěte se, že je pracovní postup nastaven na "Active", ne na "Draft"
2. **Podmínky spouštěče nesplněny**: Ověřte, že spouštěč odpovídá očekávané události
3. **Pole není sledováno**: U spouštěčů "Record is Updated" se ujistěte, že je dané pole sledováno
4. **Oprávnění**: Zkontrolujte, že máte oprávnění spouštět pracovní postupy
**Řešení**:
* Verify workflow status in the workflow list
* Test with the specific action you expect to trigger it
* Review trigger configuration
* Contact your admin about permissions
* Ověřte stav pracovního postupu v seznamu pracovních postupů
* Otestujte to konkrétní akcí, u které očekáváte, že jej spustí
* Zkontrolujte konfiguraci spouštěče
* Kontaktujte svého administrátora ohledně oprávnění
### Workflow Triggers Too Early (Empty Fields)
### Spouštění pracovního postupu příliš brzy (prázdná pole)
**Symptoms**: When manually creating a record in the UI, your workflow triggers before you've had time to fill in all the fields. The workflow runs with mostly empty field values.
**Příznaky**: Při ručním vytváření záznamu v UI se váš pracovní postup spustí dříve, než máte čas vyplnit všechna pole. Pracovní postup běží převážně s prázdnými hodnotami polí.
**Why this happens**: Twenty saves everything in real-time — there's no separate "edit" vs "read" mode. When you create a record, it's saved immediately, triggering the "Record is created" event before you can fill in additional fields.
**Proč k tomu dochází**: Twenty ukládá vše v reálném čase — neexistuje oddělený režim "edit" vs "read". Když vytvoříte záznam, ihned se uloží, což vyvolá událost "Record is created" dříve, než stihnete vyplnit další pole.
**When "Record is created" works well**:
**Kdy se "Record is created" hodí**:
* Records created via API calls (fields are populated in a single request)
* Records created via import
* Automated record creation from other workflows
* Záznamy vytvořené přes volání API (pole jsou vyplněna v jednom požadavku)
* Záznamy vytvořené pomocí importu
* Automatické vytváření záznamů z jiných pracovních postupů
**Solution**: For records created manually in the UI, use **"Record is created or updated"** as your trigger instead. This way:
**Řešení**: Pro záznamy vytvořené ručně v UI použijte jako spouštěč místo toho **"Record is created or updated"**. Tímto způsobem:
* The workflow triggers after the user has finished filling in and saving the fields
* You get the complete data rather than empty values
* Pracovní postup se spustí poté, co uživatel dokončí vyplňování polí a jejich uložení
* Získáte komplet data namísto prázdných hodnot
<Tip>
If you only want the workflow to run once per record, add a Filter action to check a field like `createdAt equals updatedAt` (first save) or use a custom checkbox field to track if the workflow has already run.
Pokud chcete, aby se pracovní postup spustil jen jednou na záznam, přidejte akci Filter, která zkontroluje pole jako `createdAt equals updatedAt` (první uložení), nebo použijte vlastní zaškrtávací pole ke sledování, zda už pracovní postup běžel.
</Tip>
### Actions Failing
### Selhávající akce
**Symptoms**: Workflow runs but some actions fail.
**Příznaky**: Pracovní postup běží, ale některé akce selhávají.
**Possible Causes**:
**Možné příčiny**:
1. **Missing data**: Required fields are empty
2. **Invalid references**: Variables from previous steps don't exist
3. **API errors**: External services returning errors
4. **Permission issues**: Action requires permissions you don't have
1. **Chybějící data**: Povinná pole jsou prázdná
2. **Neplatné odkazy**: Proměnné z předchozích kroků neexistují
3. **Chyby API**: Externí služby vracejí chyby
4. **Problémy s oprávněními**: Akce vyžaduje oprávnění, která nemáte
**Řešení**:
* Check the workflow run details for error messages
* Verify all required fields have values
* Test API connections independently
* Review role permissions
* Zkontrolujte podrobnosti běhu pracovního postupu kvůli chybovým zprávám
* Ověřte, že všechna povinná pole mají hodnoty
* Otestujte připojení k API samostatně
* Projděte oprávnění rolí
### HTTP Request Errors
### Chyby požadavků HTTP
**Symptoms**: HTTP Request actions fail or return unexpected results.
**Příznaky**: Akce HTTP Request selhávají nebo vracejí neočekávané výsledky.
**Common Error Codes**:
**Běžné chybové kódy**:
* **400**: Bad request - check your request body format
* **401**: Unauthorized - verify API key
* **403**: Forbidden - check API permissions
* **404**: Not found - verify endpoint URL
* **429**: Too many requests - implement rate limiting
* **500**: Server error - external service issue
* **400**: Neplatný požadavek - zkontrolujte formát těla požadavku
* **401**: Neautorizováno - ověřte klíč API
* **403**: Zakázáno - zkontrolujte oprávnění API
* **404**: Nenalezeno - ověřte URL endpointu
* **429**: Příliš mnoho požadavků - zaveďte omezení četnosti požadavků
* **500**: Chyba serveru - problém v externí službě
**Řešení**:
* Verify API endpoint URL
* Check authentication headers
* Test the API call outside of Twenty first
* Add error handling in Code actions
* Ověřte URL endpointu API
* Zkontrolujte autentizační hlavičky
* Nejprve otestujte volání API mimo Twenty
* Přidejte zpracování chyb v akcích Code
### Code Action Errors
### Chyby akcí Code
**Symptoms**: JavaScript code fails to execute.
**Příznaky**: Kód JavaScriptu se nedaří spustit.
**Common Issues**:
**Běžné problémy**:
1. **Syntax errors**: Typos or invalid JavaScript
2. **Undefined variables**: Referencing variables that don't exist
3. **Type errors**: Operations on wrong data types
4. **Timeouts**: Code taking too long to execute
1. **Syntaktické chyby**: Překlepy nebo neplatný JavaScript
2. **Nedefinované proměnné**: Odkazování na proměnné, které neexistují
3. **Chyby typů**: Operace na nesprávných datových typech
4. **Vypršení časového limitu**: Kód se spouští příliš dlouho
**Řešení**:
* Use the built-in code editor validation
* Test code logic in a JavaScript console first
* Add console.log statements for debugging
* Simplify complex operations
* Použijte vestavěnou validaci editoru kódu
* Nejprve otestujte logiku kódu v konzoli JavaScriptu
* Přidejte výpisy console.log pro ladění
* Zjednodušte složité operace
### Email Not Sending
### E-mail se neodesílá
**Symptoms**: Send Email action doesn't deliver emails.
**Příznaky**: Akce Send Email nedoručuje e-maily.
**Possible Causes**:
**Možné příčiny**:
1. **No email account connected**: Check Settings → Accounts
2. **Invalid email address**: Recipient email is malformed
3. **Sending limits**: Email provider rate limits reached
4. **Spam filters**: Emails being blocked
1. **Není připojen e-mailový účet**: Zkontrolujte Nastavení → Účty
2. **Neplatná e-mailová adresa**: E-mail příjemce má neplatný formát
3. **Limity odesílání**: Byly dosaženy limity poskytovatele e-mailu
4. **Spamové filtry**: E-maily jsou blokovány
**Řešení**:
* Verify email account connection
* Validate recipient email addresses
* Check email provider limits
* Review email content for spam triggers
* Ověřte připojení e-mailového účtu
* Ověřte e-mailové adresy příjemců
* Zkontrolujte limity poskytovatele e-mailu
* Zkontrolujte obsah e-mailu kvůli spouštěčům spamu
## Debugging Workflows
## Ladění pracovních postupů
### Using Workflow Runs
### Používání běhů pracovního postupu
1. Go to the workflow editor
2. Open the **Runs** panel
3. Find the failed run
4. Click to see step-by-step details
5. Review error messages and output data
1. Přejděte do editoru pracovního postupu
2. Otevřete panel **Runs**
3. Najděte neúspěšný běh
4. Klikněte pro zobrazení podrobných informací krok za krokem
5. Projděte chybové zprávy a výstupní data
### Testing Individual Steps
### Testování jednotlivých kroků
1. For Code actions, use the **Test** button
2. For HTTP requests, test the endpoint separately
3. Create test records to trigger workflows
4. Use manual triggers for controlled testing
1. U akcí Code použijte tlačítko **Test**
2. U požadavků HTTP otestujte endpoint samostatně
3. Vytvářejte testovací záznamy pro spuštění pracovních postupů
4. Pro řízené testování použijte manuální spouštěče
### Common Debugging Patterns
### Běžné vzory ladění
**Add logging**:
Use Code actions to log intermediate values for debugging.
**Přidejte logování**:
Použijte akce Code k zaznamenávání mezilehlých hodnot pro ladění.
**Isolate steps**:
Test each step independently to identify failures.
**Izolujte kroky**:
Testujte každý krok samostatně, abyste identifikovali selhání.
**Check data flow**:
Verify that each step receives the expected input data.
**Zkontrolujte tok dat**:
Ověřte, že každý krok dostává očekávaná vstupní data.
## Best Practices to Avoid Issues
## Osvědčené postupy k předcházení problémům
### Before Activation
### Před aktivací
* Test thoroughly in draft mode
* Validate all API connections
* Review trigger conditions carefully
* Document expected behavior
* Důkladně testujte v režimu konceptu
* Ověřte všechna připojení k API
* Pečlivě zkontrolujte podmínky spouštěče
* Zdokumentujte očekávané chování
### During Development
### Během vývoje
* Use descriptive step names
* Add comments in Code actions
* Test with realistic data
* Plan for edge cases
* Používejte výstižné názvy kroků
* Přidejte komentáře v akcích Code
* Testujte s realistickými daty
* Plánujte i okrajové případy
### After Activation
### Po aktivaci
* Monitor initial runs closely
* Set up alerts for failures
* Review run history regularly
* Keep workflows simple when possible
* Pečlivě sledujte počáteční běhy
* Nastavte upozornění na selhání
* Pravidelně procházejte historii běhů
* Udržujte pracovní postupy co nejjednodušší
@@ -47,6 +47,16 @@ Je nach den Einstellungen Ihres Postfachs können Sie sehen:
## E-Mail-Synchronisierungsverhalten
### Sync Rate
Twenty imports emails at approximately **400 messages per minute**. This rate is currently limited by Gmail API rate limiting (and applies similarly to other providers).
For reference:
* 1,000 emails → ~2.5 minutes
* 10,000 emails → ~25 minutes
* 50,000 emails → ~2 hours
### Was synchronisiert wird
* **Externe E-Mails**: Alle E-Mails mit Kontakten außerhalb Ihrer Organisation
@@ -60,12 +70,12 @@ Je nach den Einstellungen Ihres Postfachs können Sie sehen:
* **Gruppen-E-Mails**: Verteilerlisten und Gruppen-E-Mails sind ausgeschlossen
* **Ausgeschlossene Ordner**: Ordner, die Sie nicht synchronisieren möchten (konfiguriert unter Einstellungen → Konten → E-Mail)
### Selektive Ordnersynchronisierung (Lab-Funktion)
### Selective Folder Sync
Bestimmen Sie, welche E-Mail-Ordner mit Twenty synchronisiert werden:
1. Aktivieren Sie "Nachrichtenordner" unter Einstellungen → Releases → Lab
2. Konfigurieren Sie Ordner unter Einstellungen → Konten → E-Mail
1. Go to **Settings → Accounts** and select your connected email account
2. Configure folders under the Email section
3. Wählen Sie spezifische Ordner zum Einschließen oder Ausschließen (Posteingang, Gesendet, Archiv, benutzerdefinierte Ordner)
## Fehlerbehebung bei der E-Mail-Synchronisierung
@@ -25,7 +25,7 @@ Jedes verbundene Postfach hat eigene Einstellungen:
* **E-Mail-Sichtbarkeit**: Wählen Sie aus, was Teammitglieder sehen können
* **Automatische Kontakterstellung**: Pro Postfach aktivieren/deaktivieren
* **Ordnerauswahl**: Wählen Sie, welche Ordner synchronisiert werden (Lab-Funktion)
* **Folder selection**: Choose which folders to sync
## So werden E-Mails angezeigt
@@ -7,12 +7,12 @@ description: Troubleshooting missing emails on records.
### 1. Initial Sync Still in Progress
Email sync takes time, especially for large mailboxes.
Email sync takes time, especially for large mailboxes. Twenty imports emails at approximately **400 messages per minute** (limited by Gmail API rate limiting).
* **Calendar sync**: Completes in minutes
* **Email sync**: Can take several hours for large mailboxes
* **Email sync**: Depends on mailbox size (e.g., 10,000 emails ≈ 25 minutes, 50,000 emails ≈ 2 hours)
**Solution**: Wait up to a few hours for the initial import to complete.
**Solution**: Wait for the initial import to complete. You can estimate timing based on your mailbox size.
### 2. Contact Doesn't Exist in Twenty
@@ -11,11 +11,9 @@ Standardmäßig synchronisiert Twenty alle externen E-Mails aus Ihrem verbundene
Bestimmen Sie, welche E-Mail-Ordner mit Twenty synchronisiert werden:
1. Gehen Sie zu **Einstellungen → Veröffentlichungen → Lab**
2. Aktivieren Sie **Nachrichtenordner**
3. Zurück zu **Einstellungen → Konten**
4. Wählen Sie Ihr verbundenes E-Mail-Konto aus
5. Wählen Sie, welche Ordner synchronisiert werden sollen:
1. Gehen Sie zu **Einstellungen → Konten**
2. Wählen Sie Ihr verbundenes E-Mail-Konto aus
3. Wählen Sie, welche Ordner synchronisiert werden sollen:
| Ordner | Beschreibung |
| ----------------------------- | ------------------------------------------ |
@@ -34,11 +34,10 @@ image: /images/user-guide/emails/emails_header.png
Für andere E-Mail- und Kalenderanbieter:
1. Gehen Sie zu **Einstellungen → Releases → Lab**, um die Funktion zu aktivieren
2. Zurück zu **Einstellungen → Konten**
3. SMTP-Einstellungen für E-Mail konfigurieren
4. CalDAV-Einstellungen für Kalender konfigurieren
5. Die Verbindung testen
1. Gehen Sie zu **Einstellungen → Konten**
2. SMTP-Einstellungen für E-Mail konfigurieren
3. CalDAV-Einstellungen für Kalender konfigurieren
4. Die Verbindung testen
### Mehrere Postfächer
@@ -69,13 +68,12 @@ Wählen Sie verschiedene Sichtbarkeitsstufen für Ihre E-Mails:
<Note>When enabled, contacts are automatically linked to their Company records based on their email domain. If the company doesn't exist yet, Twenty creates it for you.</Note>
### Control which emails get sync with Message Folder Selection (Lab Feature)
### Control which emails get synced with Message Folder Selection
Bestimmen Sie, welche E-Mail-Ordner mit Twenty synchronisiert werden:
1. Gehen Sie zu **Einstellungen → Releases → Lab** und aktivieren Sie **Nachrichtenordner**
2. Zurück zu **Einstellungen → Konten** und wählen Sie Ihr verbundenes E-Mail-Konto
3. Wählen Sie, welche Ordner synchronisiert werden sollen:
1. Go to **Settings → Accounts** and select your connected email account
2. Wählen Sie, welche Ordner synchronisiert werden sollen:
* **Posteingang**: Primäre eingehende E-Mails
* **Gesendet**: Ausgehende E-Mails, die Sie gesendet haben
* **Benutzerdefinierte Ordner**: Jegliche spezifischen Ordner, die Sie einbeziehen möchten
@@ -123,7 +121,7 @@ Wählen Sie aus, was für andere Benutzer in Ihrem Arbeitsbereich sichtbar wird:
**Aktualisierungen alle 5 Minuten**: Sowohl E-Mail- als auch Kalenderdaten werden automatisch alle 5 Minuten nach dem ersten Import synchronisiert.
<Note>
**Initial sync timing**: Calendar sync completes quickly (usually within minutes), while email sync takes longer for large mailboxes—up to a few hours depending on volume. Don't worry if you see contacts from calendar events appearing before your email contacts; this is normal behavior.
**Initial sync timing**: Calendar sync completes quickly (usually within minutes), while email sync takes longer for large mailboxes. Twenty imports emails at approximately **400 messages per minute** (limited by Gmail API rate limiting), so a mailbox with 10,000 emails takes about 25 minutes. Don't worry if you see contacts from calendar events appearing before your email contacts; this is normal behavior.
</Note>
## Nächste Schritte
@@ -8,6 +8,10 @@ image: /images/user-guide/reporting/pie-chart.png
<img src="/images/user-guide/reporting/pie-chart.png" alt="Dashboards" />
</Frame>
<Note>
Dashboards are currently in beta. Activate them under **Settings → Updates → Early Access**.
</Note>
## Dashboards verstehen
Dashboards in Twenty bieten eine visuelle Möglichkeit, Ihre wichtigsten Leistungskennzahlen zu verfolgen und Erkenntnisse aus Ihren CRM-Daten zu gewinnen.
@@ -1,122 +1,122 @@
---
title: Fix Import Errors
description: Complete troubleshooting guide for resolving CSV import errors.
title: Importfehler beheben
description: Umfassende Anleitung zur Fehlerbehebung bei CSV-Importfehlern.
---
## Übersicht
Import not working? This guide helps you identify and fix common import errors step by step.
Import funktioniert nicht? Diese Anleitung hilft Ihnen, häufige Importfehler Schritt für Schritt zu erkennen und zu beheben.
## How Import Validation Works
## Wie die Importvalidierung funktioniert
After uploading your file and mapping columns, Twenty validates your data:
Nachdem Sie Ihre Datei hochgeladen und die Spalten zugeordnet haben, validiert Twenty Ihre Daten:
1. **Validation runs** — Twenty checks each row for errors
2. **Errors are highlighted** — problematic rows appear in **yellow**
3. **You can fix in-place** — edit cells directly in the import UI
4. **Or remove rows** — skip problematic records entirely
1. **Validierung läuft** — Twenty prüft jede Zeile auf Fehler
2. **Fehler werden hervorgehoben** — problematische Zeilen erscheinen in **gelb**
3. **Sie können direkt korrigieren** — bearbeiten Sie Zellen direkt in der Import-UI
4. **Oder Zeilen entfernen** — problematische Datensätze vollständig überspringen
<Note>**Fix errors in the UI.** You don't need to go back to your spreadsheet. Edit cells directly during import to save time.</Note>
<Note>**Beheben Sie Fehler in der UI.** Sie müssen nicht zu Ihrer Tabellenkalkulation zurückkehren. Bearbeiten Sie Zellen direkt während des Imports, um Zeit zu sparen.</Note>
## Step-by-Step Troubleshooting
## Schritt-für-Schritt-Fehlerbehebung
### Step 1: Identify the Error Type
### Schritt 1: Fehlertyp bestimmen
Click on a highlighted row to see the specific error message. Common error types:
Klicken Sie auf eine hervorgehobene Zeile, um die spezifische Fehlermeldung anzuzeigen. Häufige Fehlertypen:
| Fehlermeldung | What It Means |
| --------------------------------------------------------------------- | ------------------------------------------------------------ |
| Duplicate values highlighted in yellow | Value already exists in Twenty or appears twice in your file |
| `{field} is not a valid {type}` (hover on yellow cell) | Data doesn't match expected format |
| Required field highlighted | A required field is empty |
| `Can't connect to {object}. No unique record found...` (import fails) | Referenced record doesn't exist |
| `Too many records. Up to 10000 allowed` (upload blocked) | File has more than 10,000 records |
| Fehlermeldung | Was es bedeutet |
| ------------------------------------------------------------------------------ | ---------------------------------------------------------------------- |
| Doppelte Werte, gelb hervorgehoben | Wert existiert bereits in Twenty oder kommt in Ihrer Datei doppelt vor |
| `{field} is not a valid {type}` (fahren Sie mit der Maus über die gelbe Zelle) | Daten entsprechen nicht dem erwarteten Format |
| Erforderliches Feld hervorgehoben | Erforderliches Feld ist leer |
| `Can't connect to {object}. No unique record found...` (Import schlägt fehl) | Referenzierter Datensatz existiert nicht |
| `Too many records. Up to 10000 allowed` (Upload blockiert) | Die Datei enthält mehr als 10.000 Datensätze |
### Step 2: Fix the Error
### Schritt 2: Fehler beheben
Follow the specific instructions below for each error type.
Befolgen Sie die unten stehenden spezifischen Anweisungen für jeden Fehlertyp.
---
## Error: Duplicate Value
## Fehler: Doppelter Wert
### Was Sie sehen werden
Rows with duplicate values are **highlighted in yellow** in the import UI before the import starts.
Zeilen mit doppelten Werten werden in der Import-UI **gelb hervorgehoben**, bevor der Import startet.
### What It Means
### Was es bedeutet
A unique field (email, domain) either:
Ein eindeutiges Feld (E-Mail, Domain) entweder:
* Already exists in Twenty
* Appears twice in your file
* Existiert bereits in Twenty
* Kommt in Ihrer Datei doppelt vor
### How to Fix
### So beheben Sie den Fehler
**Option 1: Edit the duplicate value**
**Option 1: Doppelt vorhandenen Wert bearbeiten**
1. Click the cell with the error
2. Change to a unique value
3. Continue with import
1. Klicken Sie auf die Zelle mit dem Fehler
2. In einen eindeutigen Wert ändern
3. Mit dem Import fortfahren
**Option 2: Remove the duplicate row**
**Option 2: Die doppelte Zeile entfernen**
1. Click the X next to the row
2. The row will be skipped during import
1. Klicken Sie auf das X neben der Zeile
2. Die Zeile wird während des Imports übersprungen
**Option 3: Let Twenty update the existing record**
**Option 3: Twenty den vorhandenen Datensatz aktualisieren lassen**
1. Ensure your file includes a unique identifier (`email`, `domain`, or `id`)
2. Map the unique identifier field
3. Twenty will update the existing record instead of creating a duplicate
1. Stellen Sie sicher, dass Ihre Datei einen eindeutigen Bezeichner enthält (`email`, `domain` oder `id`)
2. Ordnen Sie das Feld mit dem eindeutigen Bezeichner zu
3. Twenty aktualisiert den vorhandenen Datensatz, statt ein Duplikat zu erstellen
<Note>
**You can update unique fields too.**
**Sie können eindeutige Felder ebenfalls aktualisieren.**
* If you keep the `id` but change the `email` → the email will be updated
* If you keep the `email` but change the `id` → the id will be updated
* Wenn Sie die `id` beibehalten, aber die `email` ändern → die E-Mail wird aktualisiert
* Wenn Sie die `email` beibehalten, aber die `id` ändern → die ID wird aktualisiert
As long as one unique identifier matches, Twenty updates the record.
Solange ein eindeutiger Bezeichner übereinstimmt, aktualisiert Twenty den Datensatz.
</Note>
### How to Prevent This Error
### So vermeiden Sie diesen Fehler
Before importing:
Vor dem Import:
1. Sort your spreadsheet by the unique field
2. Remove duplicate rows
3. Check if records already exist in Twenty
1. Sortieren Sie Ihre Tabellenkalkulation nach dem eindeutigen Feld
2. Entfernen Sie doppelte Zeilen
3. Prüfen Sie, ob Datensätze bereits in Twenty existieren
<Warning>
**Soft-deleted records count toward uniqueness.**
**Soft-gelöschte Datensätze zählen für die Eindeutigkeit.**
Check Command MenuSee deleted records. Records there still enforce uniqueness. Permanently delete them or restore and update.
Überprüfen Sie das BefehlsmenüGelöschte Datensätze anzeigen. Die dortigen Datensätze erzwingen weiterhin die Eindeutigkeit. Löschen Sie sie dauerhaft oder stellen Sie sie wieder her und aktualisieren Sie sie.
</Warning>
For more details: [Uniqueness Constraints](/l/de/user-guide/data-migration/capabilities/uniqueness-constraints)
Weitere Details: [Eindeutigkeitsbeschränkungen](/l/de/user-guide/data-migration/capabilities/uniqueness-constraints)
---
## Error: Invalid Format
## Fehler: Ungültiges Format
### Was Sie sehen werden
The cell value is highlighted in yellow. Hover over it to see the error message:
Der Zellwert ist gelb hervorgehoben. Fahren Sie mit der Maus darüber, um die Fehlermeldung zu sehen:
```
{field name} is not a valid {field type}
```
### What It Means
### Was es bedeutet
The data doesn't match the expected format for that field type.
Die Daten entsprechen nicht dem erwarteten Format für diesen Feldtyp.
### How to Fix — By Field Type
### So beheben Sie den Fehler — nach Feldtyp
#### E-Mail
**Problem:** Invalid email format
**Solution:** Use format `name@domain.com`
**Problem:** Ungültiges E-Mail-Format
**Lösung:** Verwenden Sie das Format `name@domain.com`
```
❌ john.smith@
@@ -126,34 +126,34 @@ The data doesn't match the expected format for that field type.
#### Domäne
**Problem:** Inconsistent format may cause duplicates
**Solution:** Use `https://domain.com` format (recommended)
**Problem:** Uneinheitliches Format kann Duplikate verursachen
**Lösung:** Verwenden Sie das Format `https://domain.com` (empfohlen)
```
⚠️ acme.com (valid, but not recommended)
⚠️ www.acme.com (valid, but not recommended)
✅ https://acme.com (recommended)
⚠️ acme.com (gültig, aber nicht empfohlen)
⚠️ www.acme.com (gültig, aber nicht empfohlen)
✅ https://acme.com (empfohlen)
```
<Note>All formats are valid, but `https://domain.com` is recommended because it matches the format used by email/calendar sync. Using other formats may create duplicate companies.</Note>
<Note>Alle Formate sind gültig, aber `https://domain.com` wird empfohlen, da es dem von der E-Mail-/Kalendersynchronisierung verwendeten Format entspricht. Die Verwendung anderer Formate kann doppelte Unternehmen erzeugen.</Note>
#### Datum
**Problem:** Unrecognized date format
**Solution:** Use consistent format throughout file
**Problem:** Nicht erkanntes Datumsformat
**Lösung:** Verwenden Sie in der gesamten Datei ein einheitliches Format
```
✓ 2024-03-15 (YYYY-MM-DD - recommended)
✓ 2024-03-15 (YYYY-MM-DD - empfohlen)
✓ 03/15/2024 (MM/DD/YYYY)
✓ 15/03/2024 (DD/MM/YYYY)
```
#### Telefon
**Problem:** Missing required columns
**Solution:** Include all phone columns
**Problem:** Erforderliche Spalten fehlen
**Lösung:** Alle Telefonspalten einschließen
| Column | Beispiel |
| Spalte | Beispiel |
| --------------------------------------- | ------------ |
| **Phones / Primary Phone Number** | `4159095555` |
| **Phones / Primary Phone Country Code** | `US` |
@@ -161,8 +161,8 @@ The data doesn't match the expected format for that field type.
#### Boolesch
**Problem:** Wrong boolean value
**Solution:** Use uppercase `TRUE` or `FALSE`
**Problem:** Falscher boolescher Wert
**Lösung:** Verwenden Sie `TRUE` oder `FALSE` in Großbuchstaben
```
❌ true
@@ -172,17 +172,17 @@ The data doesn't match the expected format for that field type.
✓ FALSE
```
#### Select / Multi-Select
#### Auswahl / Mehrfachauswahl
**Problem:** Value doesn't match existing options
**Solution:** Use **API names**, not display labels
**Problem:** Wert stimmt nicht mit vorhandenen Optionen überein
**Lösung:** Verwenden Sie **API-Namen**, nicht Anzeigenamen
How to find API names:
So finden Sie API-Namen:
1. Go to **Settings → Data Model**
2. Select the object and field
3. Enable **Advanced mode** (toggle at bottom right)
4. Use the API name (e.g., `OPTION_1`, not "Option 1")
1. Gehen Sie zu **Einstellungen → Datenmodell**
2. Wählen Sie das Objekt und das Feld aus
3. Aktivieren Sie den **Erweiterten Modus** (Schalter unten rechts)
4. Verwenden Sie den API-Namen (z. B. `OPTION_1`, nicht "Option 1")
```
❌ High Priority
@@ -191,18 +191,18 @@ How to find API names:
#### Währung
**Problem:** Missing amount or currency code
**Solution:** Fill both columns
**Problem:** Betrag oder Währungscode fehlt
**Lösung:** Beide Spalten ausfüllen
| Column | Beispiel |
| Spalte | Beispiel |
| --------------------- | --------- |
| **Amount / Amount** | `1234.56` |
| **Amount / Currency** | `USD` |
#### Nummer
**Problem:** Non-numeric characters
**Solution:** Numbers only, period for decimals
**Problem:** Nichtnumerische Zeichen
**Lösung:** Nur Zahlen, Punkt für Dezimalstellen
```
❌ $1,234.56
@@ -210,221 +210,221 @@ How to find API names:
✓ 1234.56
```
For complete format reference: [Field Mapping](/l/de/user-guide/data-migration/capabilities/field-mapping)
Vollständige Formatreferenz: [Referenz zur Feldzuordnung](/l/de/user-guide/data-migration/capabilities/field-mapping)
---
## Error: Required Field Missing
## Fehler: Erforderliches Feld fehlt
### Was Sie sehen werden
The row is highlighted in yellow with the required field cell marked.
Die Zeile ist gelb hervorgehoben, und die Zelle des erforderlichen Felds ist markiert.
### What It Means
### Was es bedeutet
A required field is empty for this row.
Ein erforderliches Feld ist in dieser Zeile leer.
### How to Fix
### So beheben Sie den Fehler
**Option 1: Enter a value**
**Option 1: Einen Wert eingeben**
1. Click the empty cell
2. Enter a value
3. Continue with import
1. Klicken Sie auf die leere Zelle
2. Geben Sie einen Wert ein
3. Mit dem Import fortfahren
**Option 2: Remove the row**
**Option 2: Die Zeile entfernen**
1. If you don't have the data, click X to skip the row
1. Wenn Ihnen die Daten fehlen, klicken Sie auf X, um die Zeile zu überspringen
### How to Prevent This Error
### So vermeiden Sie diesen Fehler
Before importing, identify required fields:
Identifizieren Sie vor dem Import die erforderlichen Felder:
1. Go to **Settings → Data Model**
2. Select your object
3. Check which fields are marked as required
1. Gehen Sie zu **Einstellungen → Datenmodell**
2. Wählen Sie Ihr Objekt aus
3. Prüfen Sie, welche Felder als erforderlich markiert sind
---
## Error: Relation Not Found
## Fehler: Relation nicht gefunden
### Was Sie sehen werden
This error appears **after the import starts** — the import fails with a message like:
Dieser Fehler tritt **nach Beginn des Imports** auf — der Import schlägt mit einer Meldung wie dieser fehl:
```
Can't connect to company. No unique record found with condition: id = 7776ee49-f608-4a77-8cc8-6fe96ae1e43f
```
This means there is no Company in Twenty with that specific identifier.
Das bedeutet, dass es in Twenty kein Unternehmen mit diesem spezifischen Bezeichner gibt.
<Note>Unlike other errors, this one is not caught during the data review step. The import will start and then fail when it encounters the missing relation.</Note>
<Note>Im Gegensatz zu anderen Fehlern wird dieser im Schritt der Datenüberprüfung nicht erkannt. Der Import startet und schlägt dann fehl, wenn die fehlende Relation auftritt.</Note>
### What It Means
### Was es bedeutet
You're trying to link to a record that doesn't exist in Twenty.
Sie versuchen, auf einen Datensatz zu verweisen, der in Twenty nicht existiert.
### How to Fix
### So beheben Sie den Fehler
**Option 1: Import parent records first**
**Option 1: Importieren Sie zuerst die übergeordneten Datensätze**
1. Cancel the current import
2. Import the parent records (e.g., Companies)
3. Then import the child records (e.g., People)
1. Brechen Sie den aktuellen Import ab
2. Importieren Sie die übergeordneten Datensätze (z. B. Unternehmen)
3. Importieren Sie anschließend die untergeordneten Datensätze (z. B. Personen)
**Option 2: Fix the reference value**
**Option 2: Korrigieren Sie den Referenzwert**
1. Check the reference value in your file
2. Ensure it exactly matches an existing record
3. Verify format: domains should be `https://domain.com`
1. Überprüfen Sie den Referenzwert in Ihrer Datei
2. Stellen Sie sicher, dass er genau mit einem vorhandenen Datensatz übereinstimmt
3. Format prüfen: Domains sollten das Format `https://domain.com` haben
**Option 3: Remove the relation**
**Option 3: Entfernen Sie die Relation**
1. Clear the cell to import without the relation
2. Add the relation manually later
1. Leeren Sie die Zelle, um ohne die Relation zu importieren
2. Fügen Sie die Relation später manuell hinzu
### How to Prevent This Error
### So vermeiden Sie diesen Fehler
1. **Import in the correct order:**
* Companies first
* People second (with company references)
* Opportunities third
1. **In der richtigen Reihenfolge importieren:**
* Zuerst Unternehmen
* Dann Personen (mit Unternehmensreferenzen)
* Als Drittes Opportunities
2. **Verify reference values:**
* Export parent records to get exact identifiers
* Use domain format `https://domain.com`
* Check for typos and case sensitivity
2. **Referenzwerte überprüfen:**
* Exportieren Sie übergeordnete Datensätze, um exakte Bezeichner zu erhalten
* Verwenden Sie das Domain-Format `https://domain.com`
* Prüfen Sie auf Tippfehler und Groß-/Kleinschreibung
<Warning>
**Import will fail if a reference is made to a non-existent record.**
**Der Import schlägt fehl, wenn auf einen nicht vorhandenen Datensatz verwiesen wird.**
Always import parent objects before child objects.
Importieren Sie übergeordnete Objekte immer vor untergeordneten Objekten.
</Warning>
For more details: [Import Relations](/l/de/user-guide/data-migration/capabilities/import-relations)
Weitere Details: [Beziehungen importieren](/l/de/user-guide/data-migration/capabilities/import-relations)
---
## Error: File Too Large
## Fehler: Datei zu groß
### Was Sie sehen werden
This error appears **when uploading your file** — the upload is blocked entirely:
Dieser Fehler tritt **beim Hochladen Ihrer Datei** auf — der Upload wird vollständig blockiert:
```
Too many records. Up to 10000 allowed
```
You won't be able to proceed to the data review step until you reduce the file size.
Sie können erst mit dem Schritt der Datenüberprüfung fortfahren, wenn Sie die Dateigröße reduziert haben.
### What It Means
### Was es bedeutet
Your file has more than 10,000 records.
Ihre Datei enthält mehr als 10.000 Datensätze.
### How to Fix
### So beheben Sie den Fehler
**Option 1: Split into multiple files**
**Option 1: In mehrere Dateien aufteilen**
1. Divide your data into files of 10,000 records or fewer
2. Import each file separately
3. Maintain import order (Companies before People)
1. Teilen Sie Ihre Daten in Dateien mit 10.000 oder weniger Datensätzen auf
2. Importieren Sie jede Datei separat
3. Halten Sie die Importreihenfolge ein (Unternehmen vor Personen)
**Option 2: Use API import**
For very large datasets, use the API which has no record limit.
See: [How to Import Data via API](/l/de/user-guide/data-migration/how-tos/import-data-via-api)
**Option 2: API-Import verwenden**
Für sehr große Datensätze verwenden Sie die API, die keine Datensatzbegrenzung hat.
Siehe: [So importieren Sie Daten über die API](/l/de/user-guide/data-migration/how-tos/import-data-via-api)
---
## Error: Field Not Recognized
## Fehler: Feld nicht erkannt
### What It Means
### Was es bedeutet
A column in your file can't be mapped because the field doesn't exist in Twenty.
Eine Spalte in Ihrer Datei kann nicht zugeordnet werden, weil das Feld in Twenty nicht existiert.
### How to Fix
### So beheben Sie den Fehler
1. Go to **Settings → Data Model**
2. Select the object you're importing
3. Click **+ Add field**
4. Create the custom field with the appropriate type
5. Re-upload your file
1. Gehen Sie zu **Einstellungen → Datenmodell**
2. Wählen Sie das Objekt aus, das Sie importieren
3. Klicken Sie auf **+ Feld hinzufügen**
4. Erstellen Sie das benutzerdefinierte Feld mit dem passenden Typ
5. Laden Sie Ihre Datei erneut hoch
<Note>The CSV import creates records, not fields. All fields must exist before importing.</Note>
<Note>Der CSV-Import erstellt Datensätze, nicht Felder. Alle Felder müssen vor dem Import vorhanden sein.</Note>
---
## Error: User Relation Empty
## Fehler: Benutzerrelation leer
### What It Means
### Was es bedeutet
You're trying to assign a record to a user (Owner, Assignee) but the relation isn't being mapped.
Sie versuchen, einen Datensatz einem Benutzer zuzuweisen (Owner, Assignee), aber die Relation wird nicht zugeordnet.
### Common Causes
### Häufige Ursachen
1. **User hasn't accepted their invitation** — the user doesn't exist in Twenty yet
2. **Using user ID from old system** — Twenty can't match IDs from another system
3. **Wrong email format** — the email doesn't match the user's Twenty account
1. **Benutzer hat seine Einladung nicht angenommen** — der Benutzer existiert noch nicht in Twenty
2. **Benutzer-ID aus altem System verwendet** — Twenty kann IDs aus einem anderen System nicht zuordnen
3. **Falsches E-Mail-Format** — die E-Mail entspricht nicht dem Twenty-Konto des Benutzers
### How to Fix
### So beheben Sie den Fehler
1. Ensure all users have **accepted their invitation** to your Twenty workspace
2. Use the user's **email address** (not their name or old system ID)
3. Use the same email they used to join Twenty
1. Stellen Sie sicher, dass alle Benutzer **ihre Einladung** zu Ihrem Twenty-Arbeitsbereich **angenommen haben**
2. Verwenden Sie die **E-Mail-Adresse** des Benutzers (nicht seinen Namen oder die alte System-ID)
3. Verwenden Sie dieselbe E-Mail, mit der sie Twenty beigetreten sind
<Warning>
**Users must accept invitations before importing.**
**Benutzer müssen Einladungen vor dem Import annehmen.**
If a user hasn't accepted their invitation, records referencing them will have empty user relations.
Wenn ein Benutzer seine Einladung nicht angenommen hat, haben Datensätze, die auf ihn verweisen, leere Benutzerrelationen.
</Warning>
---
## Pre-Import Checklist
## Checkliste vor dem Import
Avoid errors by checking these before importing:
Vermeiden Sie Fehler, indem Sie vor dem Import Folgendes prüfen:
### File Requirements
### Dateianforderungen
<Check>File is CSV, XLSX, or XLS format</Check>
<Check>File has fewer than 10,000 records</Check>
<Check>File uses UTF-8 encoding</Check>
<Check>Datei ist im CSV-, XLSX- oder XLS-Format</Check>
<Check>Datei enthält weniger als 10.000 Datensätze</Check>
<Check>Datei verwendet UTF-8-Kodierung</Check>
### Data Quality
### Datenqualität
<Check>No duplicate emails (for People)</Check>
<Check>No duplicate domains (for Companies)</Check>
<Check>All dates use consistent format</Check>
<Check>All domains use `https://domain.com` format</Check>
<Check>Keine doppelten E-Mails (für Personen)</Check>
<Check>Keine doppelten Domains (für Unternehmen)</Check>
<Check>Alle Datumsangaben verwenden ein einheitliches Format</Check>
<Check>Alle Domains verwenden das Format `https://domain.com`</Check>
### Field Formats
### Feldformate
<Check>Boolean fields use `TRUE` or `FALSE` (uppercase)</Check>
<Check>Select fields use API names, not display labels</Check>
<Check>Phone fields have all required columns</Check>
<Check>Currency fields have both Amount and Currency Code</Check>
<Check>Boolesche Felder verwenden `TRUE` oder `FALSE` (Großbuchstaben)</Check>
<Check>Auswahlfelder verwenden API-Namen, nicht Anzeigenamen</Check>
<Check>Telefonfelder enthalten alle erforderlichen Spalten</Check>
<Check>Währungsfelder enthalten sowohl Betrag als auch Währungscode</Check>
### Beziehungen
<Check>Parent records imported before child records</Check>
<Check>Relation columns reference existing records</Check>
<Check>Domain format matches Twenty's format exactly</Check>
<Check>Übergeordnete Datensätze vor untergeordneten Datensätzen importiert</Check>
<Check>Relationsspalten verweisen auf vorhandene Datensätze</Check>
<Check>Domain-Format entspricht exakt dem Format von Twenty</Check>
### Datenmodell
<Check>All custom fields exist in Settings → Data Model</Check>
<Check>Select options exist before importing</Check>
<Check>Alle benutzerdefinierten Felder existieren in Einstellungen → Datenmodell</Check>
<Check>Auswahloptionen existieren vor dem Import</Check>
---
## Still Having Issues?
## Gibt es weiterhin Probleme?
If you've tried the above solutions:
Wenn Sie die obigen Lösungen ausprobiert haben:
1. **Download the sample file** — see the exact format Twenty expects
2. **Export existing records** — compare your file to working data
3. **Test with a small batch** — try 5-10 rows first
4. **Check the reference articles:**
* [Field Mapping](/l/de/user-guide/data-migration/capabilities/field-mapping)
* [Uniqueness Constraints](/l/de/user-guide/data-migration/capabilities/uniqueness-constraints)
* [Import Relations](/l/de/user-guide/data-migration/capabilities/import-relations)
* [Error Handling](/l/de/user-guide/data-migration/capabilities/error-handling)
1. **Beispieldatei herunterladen** — sehen Sie das genaue Format, das Twenty erwartet
2. **Bestehende Datensätze exportieren** — vergleichen Sie Ihre Datei mit funktionierenden Daten
3. **Testen Sie mit einer kleinen Stichprobe** — probieren Sie zuerst 5-10 Zeilen
4. **Prüfen Sie die Referenzartikel:**
* [Feldzuordnung](/l/de/user-guide/data-migration/capabilities/field-mapping)
* [Eindeutigkeitsbeschränkungen](/l/de/user-guide/data-migration/capabilities/uniqueness-constraints)
* [Beziehungen importieren](/l/de/user-guide/data-migration/capabilities/import-relations)
* [Fehlerbehandlung](/l/de/user-guide/data-migration/capabilities/error-handling)
@@ -1,103 +1,103 @@
---
title: Import Relations Between Objects via CSV
description: Complete step-by-step guide to linking records during CSV import.
title: Beziehungen zwischen Objekten per CSV importieren
description: Vollständige Schritt-für-Schritt-Anleitung zum Verknüpfen von Datensätzen während des CSV-Imports.
---
## Übersicht
This guide walks you through importing relations between objects—for example, linking People to Companies, or Opportunities to People.
Diese Anleitung führt Sie durch den Import von Beziehungen zwischen Objekten zum Beispiel das Verknüpfen von Personen mit Unternehmen oder von Opportunities mit Personen.
<Note>**What can be imported:** Only one-to-many relations pointing to a single object type. Relations pointing to multiple object types (like Notes linking to People AND Companies) are not yet supported for import.</Note>
<Note>**Was kann importiert werden:** Nur Eins-zu-Viele-Beziehungen, die auf einen einzelnen Objekttyp verweisen. Beziehungen, die auf mehrere Objekttypen verweisen (z. B. Notizen, die sowohl mit Personen als auch mit Unternehmen verknüpft sind), werden beim Import noch nicht unterstützt.</Note>
## Understanding Relations
## Beziehungen verstehen
### What is a "One-to-Many" Relation?
### Was ist eine "Eins-zu-Viele"-Beziehung?
In a one-to-many relation:
In einer Eins-zu-Viele-Beziehung:
* **One** Company has **many** People (employees)
* **One** Company has **many** Opportunities
* **One** Person has **many** Tasks
* **Ein** Unternehmen hat **viele** Personen (Mitarbeitende)
* **Ein** Unternehmen hat **viele** Opportunities
* **Eine** Person hat **viele** Aufgaben
The "one" side is the **parent**. The "many" side is the **child**.
Die "Eins"-Seite ist die **übergeordnete**. Die "Viele"-Seite ist die **untergeordnete**.
### Common Relations in Twenty
### Häufige Beziehungen in Twenty
| Beziehung | "One" Side (Parent) | "Many" Side (Child) |
| ------------------------- | ------------------- | ------------------- |
| Companies → People | Unternehmen | Personen |
| Companies → Opportunities | Unternehmen | Opportunities |
| People → Tasks | Person | Aufgaben |
| People → Notes | Person | Notizen |
| Beziehung | "Eins"-Seite (übergeordnet) | "Viele"-Seite (untergeordnet) |
| --------------------------- | --------------------------- | ----------------------------- |
| Unternehmen → Personen | Unternehmen | Personen |
| Unternehmen → Opportunities | Unternehmen | Opportunities |
| Personen → Aufgaben | Person | Aufgaben |
| Personen → Notizen | Person | Notizen |
## Step 1: Identify the "One" and "Many" Sides
## Schritt 1: Identifizieren Sie die "Eins"- und "Viele"-Seiten
Before importing, determine which object is the parent and which is the child.
Bestimmen Sie vor dem Import, welches Objekt übergeordnet und welches untergeordnet ist.
**Ask yourself:** "Does ONE [Object A] have MANY [Object B]?"
**Fragen Sie sich:** "Hat EIN [Objekt A] VIELE [Objekt B]?"
* One Company → Many People ✓ (Company is parent)
* One Person → Many Companies ✗ (This is wrong—a person belongs to one company)
* Ein Unternehmen → Viele Personen ✓ (Unternehmen ist übergeordnet)
* Eine Person → Viele Unternehmen ✗ (Das ist falsch eine Person gehört zu einem Unternehmen)
## Step 2: Import the Parent Records First
## Schritt 2: Importieren Sie zuerst die übergeordneten Datensätze
The parent ("one" side) must exist in Twenty before you can reference it.
Das übergeordnete Objekt ("Eins"-Seite) muss in Twenty existieren, bevor Sie darauf verweisen können.
**Import order:**
**Importreihenfolge:**
1. **Companies** first (no dependencies)
2. **People** second (link to Companies)
3. **Opportunities** third (link to Companies and/or People)
4. **Tasks/Notes** (link to any of the above)
1. Zuerst **Unternehmen** (keine Abhängigkeiten)
2. **Personen** an zweiter Stelle (mit Unternehmen verknüpfen)
3. **Opportunities** an dritter Stelle (mit Unternehmen und/oder Personen verknüpfen)
4. **Aufgaben/Notizen** (mit einem der oben genannten verknüpfen)
<Warning>
**If the parent record doesn't exist, the import will fail.**
**Wenn der übergeordnete Datensatz nicht existiert, schlägt der Import fehl.**
Always verify that Companies are imported before importing People with company references.
Stellen Sie stets sicher, dass Unternehmen importiert sind, bevor Sie Personen mit Unternehmensreferenzen importieren.
</Warning>
## Step 3: Note the Parent's Unique Identifier
## Schritt 3: Notieren Sie den eindeutigen Bezeichner des übergeordneten Objekts
You need to reference the parent record using a **unique identifier**. Available options:
Sie müssen auf den übergeordneten Datensatz mit einem eindeutigen Bezeichner verweisen. Verfügbare Optionen:
| Parent Object | Available Unique Identifiers |
| ------------------------------ | --------------------------------------------------------------- |
| **Companies** | `id` (UUID), `domain` (recommended), or any custom unique field |
| **People** | `id` (UUID), `email`, or any custom unique field |
| **Arbeitsbereichsmitglieder** | `id` (UUID), `email` (not name) |
| **Benutzerdefinierte Objekte** | `id` (UUID), or any field marked as unique |
| Übergeordnetes Objekt | Verfügbare eindeutige Bezeichner |
| ------------------------------ | ------------------------------------------------------------------------------------------ |
| **Unternehmen** | `id` (UUID), `domain` (empfohlen) oder ein beliebiges benutzerdefiniertes eindeutiges Feld |
| **Personen** | `id` (UUID), `email` oder ein beliebiges benutzerdefiniertes eindeutiges Feld |
| **Arbeitsbereichsmitglieder** | `id` (UUID), `email` (nicht Name) |
| **Benutzerdefinierte Objekte** | `id` (UUID) oder ein beliebiges als eindeutig markiertes Feld |
<Note>**Recommended:** Use `domain` for Companies and `email` for People. These are human-readable and easy to verify in your spreadsheet.</Note>
<Note>**Empfehlung:** Verwenden Sie `domain` für Unternehmen und `email` für Personen. Diese sind menschenlesbar und in Ihrer Tabelle leicht zu überprüfen.</Note>
### Finding the Identifier
### Den Bezeichner finden
If you need the `id`:
Wenn Sie die `id` benötigen:
1. Export the parent records from Twenty
2. The export includes the `id` column
3. Use these IDs in your child records file
1. Exportieren Sie die übergeordneten Datensätze aus Twenty
2. Der Export enthält die Spalte `id`
3. Verwenden Sie diese IDs in Ihrer Datei mit untergeordneten Datensätzen
## Step 4: Verify the Relation Field Exists
## Schritt 4: Überprüfen Sie, ob das Beziehungsfeld existiert
Before importing, ensure the relation field exists between your objects.
Stellen Sie vor dem Import sicher, dass das Beziehungsfeld zwischen Ihren Objekten existiert.
**To check or create:**
**So prüfen oder erstellen Sie es:**
1. Go to **Settings → Data Model**
2. Select your child object (e.g., People)
3. Look for a relation field pointing to the parent (e.g., Company)
4. If it doesn't exist, create it:
* Click **+ Add field**
* Select **Relation** type
* Choose the parent object
1. Gehen Sie zu **Einstellungen → Datenmodell**
2. Wählen Sie Ihr untergeordnetes Objekt aus (z. B. Personen)
3. Suchen Sie nach einem Beziehungsfeld, das auf das übergeordnete Objekt zeigt (z. B. Unternehmen)
4. Wenn es nicht existiert, erstellen Sie es:
* Klicken Sie auf **+ Feld hinzufügen**
* Wählen Sie den Typ **Relation**
* Wählen Sie das übergeordnete Objekt
## Step 5: Prepare Your CSV File
## Schritt 5: Bereiten Sie Ihre CSV-Datei vor
Add a column to your child CSV that references the parent using its unique identifier.
Fügen Sie Ihrer untergeordneten CSV eine Spalte hinzu, die mit dem eindeutigen Bezeichner auf das übergeordnete Objekt verweist.
### Example: People Linking to Companies
### Beispiel: Personen, die mit Unternehmen verknüpft werden
**Your People CSV:**
**Ihre Personen-CSV:**
```csv
firstName,lastName,email,jobTitle,companyDomain
@@ -106,66 +106,66 @@ Jane,Doe,jane@widgets.co,CTO,https://widgets.co
Bob,Johnson,bob@techstart.io,Developer,https://techstart.io
```
The `companyDomain` column references the Company's domain.
Die Spalte `companyDomain` verweist auf die Domain des Unternehmens.
### Format Requirements
### Formatvorgaben
| Kennung | Format | Beispiel |
| ------- | -------------- | -------------------------------------- |
| Domäne | URL format | `https://acme.com` |
| E-Mail | Standard email | `john@acme.com` |
| ID | UUID | `c776ee49-f608-4a77-8cc8-6fe96ae1e43f` |
| Kennung | Format | Beispiel |
| ------- | --------------- | -------------------------------------- |
| Domäne | URL-Format | `https://acme.com` |
| E-Mail | Standard-E-Mail | `john@acme.com` |
| ID | UUID | `c776ee49-f608-4a77-8cc8-6fe96ae1e43f` |
<Warning>
**Domain format matters!**
**Das Domain-Format ist wichtig!**
Use `https://domain.com` (not just `domain.com`). This matches how Twenty stores Company domains and prevents matching errors.
Verwenden Sie `https://domain.com` (nicht nur `domain.com`). Dies entspricht der Art, wie Twenty Unternehmensdomains speichert, und verhindert Zuordnungsfehler.
</Warning>
### Important Rules
### Wichtige Regeln
1. **Exact match required** — the value must exactly match the parent record
2. **Map only ONE unique identifier** — don't include both `companyId` AND `companyDomain`
3. **Case sensitive** — `Acme.com` ≠ `acme.com`
1. **Exakte Übereinstimmung erforderlich** — der Wert muss exakt dem übergeordneten Datensatz entsprechen
2. **Nur EINEN eindeutigen Bezeichner zuordnen** — geben Sie nicht sowohl `companyId` als auch `companyDomain` an
3. **Groß-/Kleinschreibung beachten** — `Acme.com` ≠ `acme.com`
## Step 6: Upload and Map the Relation
## Schritt 6: Beziehung hochladen und zuordnen
1. Navigate to the child object (e.g., People)
2. Click **⋮** → **Import records**
3. Upload your CSV file
4. In the field mapping step:
* Find your relation column (e.g., `companyDomain`)
* Map it to the **Company** relation field
5. Complete the remaining mapping
6. Review errors and confirm
1. Navigieren Sie zum untergeordneten Objekt (z. B. Personen)
2. Klicken Sie auf **⋮** → **Datensätze importieren**
3. Laden Sie Ihre CSV-Datei hoch
4. Im Schritt zur Feldzuordnung:
* Suchen Sie Ihre Beziehungsspalte (z. B. `companyDomain`)
* Ordnen Sie sie dem **Company**-Beziehungsfeld zu
5. Schließen Sie die übrige Zuordnung ab
6. Prüfen Sie Fehler und bestätigen Sie
Twenty will automatically link each child record to the matching parent.
Twenty verknüpft automatisch jeden untergeordneten Datensatz mit dem passenden übergeordneten Datensatz.
## Step 7: Verify the Import
## Schritt 7: Überprüfen Sie den Import
After importing:
Nach dem Import:
1. Open a few child records (e.g., People)
2. Verify the relation field shows the correct parent (e.g., Company)
3. Open a parent record and check the related records section
1. Öffnen Sie einige untergeordnete Datensätze (z. B. Personen)
2. Überprüfen Sie, ob das Beziehungsfeld das richtige übergeordnete Objekt anzeigt (z. B. Unternehmen)
3. Öffnen Sie einen übergeordneten Datensatz und prüfen Sie den Bereich mit den zugehörigen Datensätzen
## Common Mistakes to Avoid
## Häufige Fehler, die Sie vermeiden sollten
| Mistake | Problem | Solution |
| -------------------------- | -------------------------------------------------- | ------------------------------------------------------- |
| **Wrong import order** | Importing People before Companies | Always import parents first, then children |
| **Wrong domain format** | Using `acme.com` instead of `https://acme.com` | Use full URL format with `https://` |
| **Multiple unique fields** | Mapping both `companyId` AND `companyDomain` | Map only ONE unique identifier |
| **Missing relation field** | The relation field doesn't exist in the data model | Create it in **Settings → Data Model** before importing |
| **Non-existent records** | The parent record doesn't exist in Twenty | Import parent records first, or check for typos |
| **Case mismatch** | `Acme.com` in file but `acme.com` in Twenty | Ensure exact case matching |
| Fehler | Problem | Lösung |
| ------------------------------------------ | --------------------------------------------------------- | -------------------------------------------------------------------------------- |
| **Falsche Importreihenfolge** | Personen vor Unternehmen importieren | Importieren Sie immer zuerst übergeordnete, dann untergeordnete Datensätze |
| **Falsches Domain-Format** | Verwendung von `acme.com` statt `https://acme.com` | Verwenden Sie das vollständige URL-Format mit `https://` |
| **Mehrere eindeutige Felder** | Zuordnung sowohl von `companyId` als auch `companyDomain` | Ordnen Sie nur EINEN eindeutigen Bezeichner zu |
| **Beziehungsfeld fehlt** | Das Beziehungsfeld existiert nicht im Datenmodell | Erstellen Sie es vor dem Import unter **Einstellungen → Datenmodell** |
| **Nicht vorhandene Datensätze** | Der übergeordnete Datensatz existiert in Twenty nicht | Importieren Sie zunächst übergeordnete Datensätze oder prüfen Sie auf Tippfehler |
| **Unterschiedliche Groß-/Kleinschreibung** | `Acme.com` in der Datei, aber `acme.com` in Twenty | Achten Sie auf exakt übereinstimmende Groß-/Kleinschreibung |
## Linking to Workspace Members
## Verknüpfen mit Teammitgliedern
When linking to Workspace Members (your team):
Beim Verknüpfen mit Teammitgliedern (Ihrem Team):
* Use their **email address**, not their name
* Example: `owner@yourcompany.com`, not "John Smith"
* Verwenden Sie ihre **E-Mail-Adresse**, nicht ihren Namen
* Beispiel: `owner@yourcompany.com`, nicht "John Smith"
```csv
taskName,assignedTo
@@ -176,53 +176,53 @@ Review proposal,jane@yourcompany.com
## FAQ
<AccordionGroup>
<Accordion title="What if my parent record doesn't have a domain or email?">
You have two options:
<Accordion title="Was ist, wenn mein übergeordneter Datensatz keine Domain oder E-Mail hat?">
Sie haben zwei Optionen:
1. Use the Twenty `id` (export parent records to get their IDs)
2. Create a custom unique field in your data model to store an external ID from your previous system
1. Verwenden Sie die Twenty-`id` (exportieren Sie übergeordnete Datensätze, um ihre IDs zu erhalten)
2. Erstellen Sie ein benutzerdefiniertes eindeutiges Feld in Ihrem Datenmodell, um eine externe ID aus Ihrem vorherigen System zu speichern
</Accordion>
<Accordion title="Can I update relations on existing records?">
Ja! Include the child record's unique identifier (e.g., `email` for People) and the new relation value. The import will update the relation.
<Accordion title="Kann ich Beziehungen bei bestehenden Datensätzen aktualisieren?">
Ja! Geben Sie den eindeutigen Bezeichner des untergeordneten Datensatzes (z. B. `email` für Personen) und den neuen Beziehungswert an. Beim Import wird die Beziehung aktualisiert.
</Accordion>
<Accordion title="Can I import Many-to-Many relationships?">
Many-to-Many relations are not yet supported for import. This is planned for H1 2026.
<Accordion title="Kann ich Viele-zu-Viele-Beziehungen importieren?">
Viele-zu-Viele-Beziehungen werden beim Import noch nicht unterstützt. Dies ist für H1 2026 geplant.
</Accordion>
<Accordion title="Can I link to multiple object types (like Notes to People AND Companies)?">
Relations pointing to multiple object types are not yet supported for import/export. This is on our roadmap.
<Accordion title="Kann ich mit mehreren Objekttypen verknüpfen (z. B. Notizen mit Personen UND Unternehmen)?">
Beziehungen, die auf mehrere Objekttypen zeigen, werden für Import/Export noch nicht unterstützt. Dies steht auf unserer Roadmap.
</Accordion>
<Accordion title="What happens if a parent record doesn't exist?">
The import will show an error for that row. Sie können entweder:
<Accordion title="Was passiert, wenn ein übergeordneter Datensatz nicht existiert?">
Der Import zeigt für diese Zeile einen Fehler an. Sie können entweder:
* Import the parent record first, then re-import
* Fix the reference value
* Remove the row from import
* Importieren Sie zuerst den übergeordneten Datensatz und importieren Sie dann erneut
* Korrigieren Sie den Referenzwert
* Entfernen Sie die Zeile aus dem Import
</Accordion>
<Accordion title="Why is my relation not linking correctly?">
Common causes:
<Accordion title="Warum wird meine Beziehung nicht korrekt verknüpft?">
Häufige Ursachen:
* Wrong format (use `https://domain.com` for domains)
* Case mismatch (check exact spelling)
* Parent doesn't exist (import parents first)
* Mapping multiple identifiers (use only one)
* Falsches Format (verwenden Sie für Domains `https://domain.com`)
* Abweichende Groß-/Kleinschreibung (prüfen Sie die exakte Schreibweise)
* Übergeordneter Datensatz existiert nicht (zuerst übergeordnete Datensätze importieren)
* Zuordnung mehrerer Bezeichner (verwenden Sie nur einen)
</Accordion>
</AccordionGroup>
<Warning>
**Remember: Soft-deleted records count toward uniqueness.**
**Denken Sie daran: soft gelöschte Datensätze zählen für die Eindeutigkeit.**
If you're getting "not found" errors but the record seems to exist, check Command Menu → See deleted records. The parent may have been soft-deleted.
Wenn Sie "not found"-Fehler erhalten, der Datensatz aber zu existieren scheint, prüfen Sie im Befehlsmenü → Gelöschte Datensätze anzeigen. Der übergeordnete Datensatz wurde möglicherweise soft gelöscht.
</Warning>
## Fehlerbehebung
Having issues? Check:
Gibt es Probleme? Prüfen Sie:
* [How to Fix Import Errors](/l/de/user-guide/data-migration/how-tos/fix-import-errors)
* [Import Relations Capabilities](/l/de/user-guide/data-migration/capabilities/import-relations)
* [Uniqueness Constraints](/l/de/user-guide/data-migration/capabilities/uniqueness-constraints)
* [So beheben Sie Importfehler](/l/de/user-guide/data-migration/how-tos/fix-import-errors)
* [Funktionen zum Import von Beziehungen](/l/de/user-guide/data-migration/capabilities/import-relations)
* [Eindeutigkeitsbeschränkungen](/l/de/user-guide/data-migration/capabilities/uniqueness-constraints)

Some files were not shown because too many files have changed in this diff Show More