Compare commits

..
Author SHA1 Message Date
Sonarly Claude Code d9aa0f9b5b chore: improve monitoring for fix(front): guard undefined recordNode in cache ma
Added code-level monitoring in `getRecordsFromRecordConnection` for malformed connection payloads: edges with missing `node` are now filtered out (to avoid downstream failures) and reported to Sentry as a warning-level message with grouped fingerprint and counts (`invalidEdgeCount`, `edgesCount`). This reduces noisy high-severity exception capture while preserving actionable signal about data-shape anomalies.
2026-05-12 09:48:51 +00:00
Sonarly Claude Code a9b7ec8cb0 fix(front): guard undefined recordNode in cache mapper
https://sonarly.com/issue/36844?type=bug

A frontend runtime error crashes a notes-page record picker flow when a record edge has an undefined node. The exception is handled by Sentry but leaves the user in a broken interaction state.

Fix: Implemented a defensive guard in `getRecordFromRecordNode` so undefined `recordNode` no longer throws during destructuring (`const { id, __typename } = recordNode`). The function now returns an empty object when `recordNode` is missing, preventing the runtime crash seen in Notes relation picker flow. Added a unit regression test and snapshot to lock this behavior.
2026-05-12 09:48:51 +00:00
Charles BochetandGitHub 5003fcbbf2 chore: remove dead feature flags (#20460)
## Summary

Two related cleanups, following the same pattern as #19916 and #19074.

### Dead feature flags

Drops four feature flags whose only references are the enum entry and
the generated GraphQL/SDK files:

- `IS_COMMAND_MENU_ITEM_ENABLED` — never read anywhere.
- `IS_DATASOURCE_MIGRATED` — already commented `@deprecated`. Zero
non-generated consumers.
- `IS_RICH_TEXT_V1_MIGRATED` — the 1-19 migration that gated it was
removed in #19074; the flag became dead at that point.
- `IS_CONNECTED_ACCOUNT_MIGRATED` — only read by the 1-21
`migrate-messaging-infrastructure-to-metadata` command as an
early-return guard, but the flag was never written anywhere in the
codebase, so the guard never fired (and that workspace command is now
removed entirely — see below).

Generated GraphQL/SDK schemas and the `workspace-entity-manager` test
mock are trimmed to match.

### 1-21 workspace commands

Same pattern as #19074 (which removed workspace commands ≤ 1.18). Twenty
is now on 2-5; the 1-21 workspace commands have long since run on every
active workspace and are dead code.

Removes:

- All 14 workspace commands under `upgrade-version-command/1-21/`
(compose-email menu item, key-value-pair index, datasource backfill,
message-thread backfill, dedup engine commands, select-all fixes, AI
response format migration, edit-layout label, drop messaging FKs, folder
parent-id migration, messaging-infra-to-metadata, navigation refactor,
message-thread label fix, search-menu-item label).
- The `1-21-upgrade-version-command.module.ts` registration and the
`V1_21_UpgradeVersionCommandModule` import from
`WorkspaceCommandProviderModule`.

**Kept** (intentionally): the 3 `1-21-instance-command-fast-*` files.
Unlike workspace commands (which mutate data), instance commands carry
**schema deltas** still required by current entity definitions
(`AddViewFieldGroupIdIndex`, `MigrateMessagingCalendarToCore`,
`AddEmailThreadWidgetType`). They remain registered in
`INSTANCE_COMMANDS` and `'1.21.0'` stays in `TWENTY_PREVIOUS_VERSIONS`.
They will fold away naturally on a future version bump when a
`CoreMigrationCheck`-style snapshot picks them up.

## Test plan

- [x] `npx nx typecheck twenty-shared`
- [x] `npx nx typecheck twenty-server`
- [x] `npx nx typecheck twenty-front`
- [x] `npx prettier --check` on the changed files
- [x] `npx oxlint` on the changed server files
- [x] `npx jest feature-flag` (4 suites, 20 tests pass)
- [x] `npx jest workspace-entity-manager` (1 suite, 5 tests pass)
2026-05-12 11:25:20 +02:00
b6b4824104 ci(preview-env): drop yarn -- separator so --light reaches the seed command (#20479)
## Summary

Follow-up to #20464. That PR added `--light` to the preview env seed
command but left the `--` between `yarn command:prod` and the script
args. After yarn strips its own `--`, nest-commander still sees `argv:
[..., '--', 'workspace:seed:dev', '--light']`. Commander.js treats `--`
as the end-of-options marker, so `--light` is parsed as a positional arg
and silently ignored — the seed runs in full mode (Apple + YCombinator +
Empty3 + Empty4) and Empty4 still ends up as the default workspace.

## Evidence

In the preview run on `f706cc052b` (which had #20464's `--light` flag),
the seed step took only ~40s but the `GqlTypeGenerator` log emits four
regenerations across two workspaces with custom objects:

- 28 standard → 28 + 5 custom (`rocket, surveyResult, employmentHistory,
petCareAgreement, pet`) — matches Apple
- 28 standard → 28 + 1 custom (`surveyResult`) — matches YCombinator

With `--light` actually applied, `getLightConfig` returns `{ objects:
[], fields: [] }` so no custom objects should be generated.

The working `twenty-app-dev` invocation in
`packages/twenty-docker/twenty-app-dev/rootfs/etc/s6-overlay/scripts/init-db.sh:66`
is `yarn command:prod workspace:seed:dev --light` — no `--`. Matching
that fixes it.

## Test plan

- [ ] Trigger the preview-app label on a PR, confirm only the Apple
workspace is created and `tim@apple.dev` signs in there
- [ ] Confirm the seed step still passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 10:50:08 +02:00
Félix MalfaitandGitHub 8d54ff6ca0 fix(ci): probe real schema in breaking-changes server readiness check (#20465)
## Summary

The `GraphQL and OpenAPI Breaking Changes Detection` workflow has been
posting graphql-inspector stack traces as PR comments — see [#20445
comment](https://github.com/twentyhq/twenty/pull/20445#issuecomment-4421142635)
for an example.

### Root cause

- The wait step probed readiness with `curl -s URL > /dev/null 2>&1`,
which exits 0 for **any** HTTP response — including 5xx and GraphQL
error JSON. NestJS opens the HTTP listener before the workspace schema
cache is fully populated, so the wait often completed while the server
still served auth/metadata error JSON.
- The introspection download therefore wrote a small (~154-byte) error
payload instead of the real schema. `jq empty` in the validation step
only checks JSON *syntax*, so `{"errors":[...]}` passed validation.
- `graphql-inspector diff` then failed with `Unable to read JSON file:
... Not valid JSON content`, the workflow swallowed the error into the
diff markdown, and the bot posted that stack trace verbatim on the PR.

In the failing run, the main-branch files were 154 B (GraphQL) and 112 B
(REST 500); the current-branch files in the same run were 600 KB–2.8 MB.

### Fix

- Wait steps now POST an authenticated introspection (`{ __schema {
queryType { name } } }`) and require `.data.__schema` plus a 2xx
response from `/rest/open-api/core` (`curl -f`) before declaring the
server ready.
- Validation step now checks for the expected shape (`.data.__schema`
for GraphQL, `.openapi`/`.swagger` for OpenAPI) and includes the first
200 bytes of any bad payload in the warning, so when something genuinely
goes wrong the next debugger has a real lead instead of a generic stack
trace.

## Test plan

- [ ] CI runs against this branch — the workflow's own readiness probes
are now exercised against the real server, so a green run validates the
new check.
- [ ] If the readiness probe still passes but downloads regress, the
strengthened validation step will surface the payload in the workflow
logs instead of posting a graphql-inspector stack trace on the PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-12 06:43:35 +00:00
Abdul RahmanandGitHub 1adb59f7f8 Support optional labels on logic-function input schema fields (#20471)
Adds an optional label field to logic-function input schema properties
(InputSchemaProperty and InputJsonSchema). When set, the workflow
builder renders the label in place of the raw property key for both leaf
inputs and nested sections; when unset, it falls back to the key.
jsonSchemaToInputSchema propagates the label so app authors can declare
it in their JSON schema. Payload paths, the variable picker, and saved
workflow inputs continue to use the property key — labels are
display-only.
2026-05-12 06:40:10 +00:00
Abdul RahmanandGitHub 93df64b9b0 Show logic function label instead of technical name in workflow UI (#20470)
### Before
<img width="1304" height="812" alt="Screenshot 2026-05-12 at 7 02 32 AM"
src="https://github.com/user-attachments/assets/94ca4b1d-69c0-4059-8c45-dd8eae8e2a29"
/>



### After
<img width="1296" height="782" alt="Screenshot 2026-05-12 at 6 53 26 AM"
src="https://github.com/user-attachments/assets/47f2e291-73df-4471-9174-bd5aca23e228"
/>
2026-05-12 05:46:56 +00:00
a3b0a34207 Fix lint:diff-with-main oxlint rules build dependency (#20389)
## Summary

Closes #20382.

`lint:diff-with-main` can load `.oxlintrc.json` files that reference
`../twenty-oxlint-rules/dist/oxlint-plugin.mjs`, but the diff-lint
targets did not build `twenty-oxlint-rules` first. On fresh clones, that
generated plugin file is missing and oxlint fails before linting.

This PR adds `twenty-oxlint-rules:build` before diff lint for:
- the root `lint:diff-with-main` target default
- the custom `twenty-front:lint:diff-with-main` target
- the custom `twenty-server:lint:diff-with-main` target

It also adds regression coverage for:
- the default diff-lint target dependency
- the custom front/server diff-lint target dependencies
- preserving `twenty-website-new` custom dependencies because it does
not load the Twenty oxlint plugin

## Tests

- `npx vitest run --config
packages/twenty-oxlint-rules/vitest.config.mts
workspace/lint-diff-with-main-targets.spec.ts`
- `node_modules/.bin/nx test twenty-oxlint-rules`
- `node_modules/.bin/nx typecheck twenty-oxlint-rules`
- `node_modules/.bin/nx build twenty-oxlint-rules`
- `node_modules/.bin/nx lint:diff-with-main twenty-server`
- `node_modules/.bin/nx lint:diff-with-main twenty-front`
- `npx oxlint -c packages/twenty-oxlint-rules/.oxlintrc.json
packages/twenty-oxlint-rules/workspace/lint-diff-with-main-targets.spec.ts`
- `git diff --check`

## Notes

- `twenty-website-new:lint:diff-with-main` dependency shape remains
unchanged. Full local execution is blocked by missing local `unzip`,
which the existing `check-lottie-frames` script requires.

## Docs / Changelog

No docs or manual changelog update needed. This fixes Nx task wiring for
an existing documented command.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-05-11 22:03:49 +00:00
009f597eec ci(preview-env): use --light seed so Apple is the default workspace (#20464)
## Summary

- Pass `--light` to `workspace:seed:dev` in the preview env keepalive
workflow so only the Apple workspace is created
- Avoids `Empty4` being picked as the default workspace at sign-in
(which has no users), making the prefilled `tim@apple.dev` credentials
land on a useful workspace

## Why

`workspace:seed:dev` (no flag) seeds Apple + YCombinator + Empty3 +
Empty4. Preview envs run in single-workspace mode
(`IS_MULTIWORKSPACE_ENABLED=false`), so
[`WorkspaceDomainsService.getDefaultWorkspace`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service.ts)
returns the most recently created workspace — Empty4 — which has no
users. Users hitting the preview URL therefore see "Welcome, Empty4."
and can't sign in. Same failure mode #19822 fixed for `twenty-app-dev`.

## Test plan

- [ ] Trigger the `preview-app` label on a PR and confirm the preview
URL signs in to the Apple workspace, not Empty4
- [ ] Confirm the seed step still passes (no `Empty3`/`Empty4`
references break it)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 22:46:54 +02:00
b0413575f5 i18n - translations (#20461)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-05-11 22:01:37 +02:00
neo773GitHubcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
b03f044d0f feat(messaging): add workspace toggle to sync internal emails (#20457)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-05-11 19:42:51 +00:00
Charles BochetandGitHub 75c22a2119 feat(front-component-renderer): forward file input metadata (#20458)
## Summary

`<input type=\"file\">` inside front-components was silently
non-functional:
- The host-side `serializeEvent` did not read `target.files`, so the
worker received an empty `onChange` detail.
- `SerializedEventData` had no `files` field.
- The `html-input` schema in `AllowedHtmlElements` exposed neither
`accept`, `multiple`, nor `capture` — the worker could not even
configure the picker.

This PR forwards file metadata (`name`, `size`, `type`, `lastModified`)
through the existing serialized event detail and accepts the missing
attributes on the `html-input` remote element. A new Storybook play test
guards the regression by uploading single and multiple files via
`userEvent.upload`.

Reading file contents inside the worker is intentionally out of scope
here and will need a separate host API bridge (the host has the `File`
objects on the real input element; passing bytes through `postMessage`
is a bigger design call).
2026-05-11 19:30:38 +00:00
3d8207af0f ci(preview-env): replace bore.pub with Cloudflare quick tunnel (#20459)
## Summary

`bore.pub`'s public server has been increasingly unreliable: tunnels
register fine on the runner side (our `Create Tunnel` step always
succeeds), but the bore.pub side later stops accepting inbound traffic,
leaving the preview environment unreachable for the rest of the 5h
keep-alive window with no signal back to the runner. Recent symptom:
`curl http://bore.pub:50422` → `Couldn't connect to server`, while the
corresponding action keeps sleeping.

This PR replaces the `codetalkio/expose-tunnel` action with a direct
invocation of `cloudflared` running an account-less [Cloudflare quick
tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/).
The tunnel is served from Cloudflare's edge so reliability is materially
better, and the URL is HTTPS by default (`https://*.trycloudflare.com`),
which also eliminates the mixed-content issues we'd hit when
`SERVER_URL` was `http://bore.pub:port`.

## What changes

- `Create Tunnel` step now:
  - Downloads a pinned `cloudflared` binary (`2026.3.0`)
- Starts `cloudflared tunnel --url http://localhost:3000` in the
background, logging to `$RUNNER_TEMP/cloudflared.log`
- Polls the log for `https://<name>.trycloudflare.com` (up to 2
minutes), failing fast if the process exits
- Writes the URL to the `tunnel-url` step output — same name as before,
so no downstream changes needed
- `Cleanup` step kills the `cloudflared` process for hygiene

## What stays the same

- `SERVER_URL` plumbing through `.env` → `docker compose up`
- `tunnel-url` artifact
- `$GITHUB_STEP_SUMMARY` formatting
- PR-comment dispatch (`twentyhq/ci-privileged`)
- 5h keep-alive sleep

## Trade-offs

- Quick tunnels are explicitly labelled by Cloudflare for
"testing/development" use without an SLA. For our preview-env use case
(ephemeral, per-PR) that fits, but if we ever need stable URLs on a
custom domain we'd move to *named* tunnels — same `cloudflared` binary,
plus a free Cloudflare account + delegated domain + a service token
stored as a repo secret. Strictly additive when we want it.
- `cloudflared` is pinned to `2026.3.0` to avoid surprise breakage from
upstream releases. Bumping is a one-line change.

## Testing

**Locally (macOS) — verified end-to-end:**
- `cloudflared tunnel --url http://localhost:18080` against a `python3
-m http.server`
- Regex `https://[a-zA-Z0-9-]+\.trycloudflare\.com` correctly extracts
the URL from the log
- `curl $URL/` returns the upstream server's response (HTTP 200, ~0.5s)
- Process supervision: if `cloudflared` dies mid-wait, the step fails
fast instead of hitting the 2-min timeout

**Validation:**
- `actionlint` passes (the remaining shellcheck warnings are in
pre-existing steps, not my changes)
- `shellcheck` on the new Create Tunnel script: clean

**What's not testable from a PR (and why):**
- The full keep-alive workflow runs on `repository_dispatch`, which
always uses the workflow file from `main`. So the cloudflared logic only
runs against PR contents *after* merge.
- I'll trigger a one-off Ubuntu-runner test of just the install + URL
extraction logic via a throwaway branch (`workflow_dispatch`-only) and
link the run here before this merges.

## Test plan

- [ ] Throwaway run validates: cloudflared installs on `ubuntu-latest`,
prints the URL, regex matches, tunnel is reachable from outside the
runner.
- [ ] After merge, the next PR's preview environment uses
`*.trycloudflare.com` instead of `bore.pub:port`, and the URL stays
reachable for the full 5h window.
- [ ] PR-comment bot still posts the preview URL correctly (link should
now be `https://*.trycloudflare.com`).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 21:39:22 +02:00
Priyanshu BartwalandGitHub c227b0d06a Fix(UI): Side panel having two scrollbars (#20456)
Fixes: #20417

Screenshot:
<img width="411" height="945" alt="image"
src="https://github.com/user-attachments/assets/925b3ac9-49f2-4fcc-920e-3b9dc34ac466"
/>
2026-05-11 18:42:55 +00:00
f634a4a0c0 fix(front-component): preserve caret position on controlled input/textarea updates (#20416)
## Problem

In the front-component sandbox, typing in the middle of a pre-filled
`<input>` or `<textarea>` caused the caret to jump to the end on every
keystroke. Characters appeared at the correct position, but editing
mid-string was effectively broken.

Root cause: the remote-DOM bridge round-trips every keystroke through
the
worker. By the time the updated `value` prop arrives back at the host,
React applies it by setting `inputElement.value = X` directly, which
browsers always reset the caret to the end.

Typing at the end was unaffected, which is why this went unnoticed in
search fields and similar append-only inputs.

## Fix

For text-like `<input>` types and `<textarea>`, the `value` prop is now
applied imperatively through a ref callback instead of being passed as a
React controlled prop:

- If the DOM value already matches the incoming prop, the assignment is
  skipped entirely.
- If a write is needed and the element is focused, `selectionStart` and
  `selectionEnd` are captured before the assignment and restored
  afterwards with `setSelectionRange`.

Non-text input types (checkbox, radio, file, color, range) and all other
host elements are unaffected.

## Testing

Drop the repro from the issue into any front-component, click between
two
characters in the pre-filled value, and type — the caret should now stay
at the insertion point.

Fixes #20409

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-05-11 17:47:30 +00:00
689ec16f50 i18n - website translations (#20454)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-05-11 18:28:11 +02:00
EtienneandGitHub 1b09c69c39 refactor(file v2) - deletion (#20356) 2026-05-11 16:16:46 +00:00
b1f7a2c544 [Website] Replace feature card screenshots with interactive visuals (#20442)
Replace static screenshot images with lightweight interactive
mini-components for all 7 feature cards (Dashboard, Tasks, Emails,
Contacts, Pipeline, Files, Data Import). Add scroll-triggered entrance
animations, shared WindowChrome component, and dark-themed visual
tokens. Remove unused screenshot assets.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 16:13:46 +00:00
Charles BochetandGitHub e7032d0638 fix: prevent admin panel workspace upgrade error from overflowing the table (#20394)
## Summary

In the admin panel workspace detail page, the **Upgrade Status > Last
error** row was rendering the raw `errorMessage` string directly. Long
messages (typically full stack traces) overflowed the table cell and
overlapped neighbouring rows, breaking the layout.

The `Last command` row in the same table already uses
`OverflowingTextWithTooltip` (the helper used elsewhere in settings
tables) to clamp long values to a single line and reveal the full text
in a tooltip on hover.

This PR applies the same treatment to the `Last error` row, with
`isTooltipMultiline` so newlines in the stack trace are preserved when
the tooltip opens.

## Test plan

- [ ] Open Admin Panel > a workspace with a failed upgrade and verify
the `Last error` row stays on a single line with an ellipsis
- [ ] Hover the row and verify the full multi-line error is shown in the
tooltip
- [ ] Verify other rows (Last command, Last updated, etc.) and the
workspace info section are unaffected
2026-05-11 15:46:57 +00:00
5f3407878d i18n - docs translations (#20451)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-05-11 17:27:46 +02:00
martmullandGitHub 7c053716ae Stop rejecting application install when APP_VERSION is wrong (#20443)
as title

allows to install https://github.com/JordanChoo/twenty-multi-pipeline
locally
2026-05-11 15:17:17 +00:00
6c18bacb93 Encrypt connected account accessToken and refreshToken (#20441)
# Introduction
Encrypt the `connectedAccount` `accessToken` and `refreshToken` using
`APP_SECRET` in order to mitigate potential data leak or `core` table
compromise

## Decrypt
Temporary allow already plain text stored token to be retrieve without
decryption until the slow instance has been passed
Will uncomment the invariant check in a patch when the instance slow has
fully be run

## Standards
- Token are encrypted as quickly as possible
- A token cannot be written in database non encrypted by mistake using a
custom constraint ( `enc:` prefix )

## What's next
We should standardize not managing secret as is in the the services and
layer, they should be encrypted on the flight the earliest and should
never be logged
Will create a dedicated pattern afterwards for `applicationVariables`
secrets too

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2026-05-11 15:16:12 +00:00
Thomas des FrancsandGitHub 93d83b2e36 [codex] Add Twenty Claude skills package (#20450)
## Summary

Adds a new `twenty-claude-skills` workspace package under `packages/`
for Claude skills related to Twenty.

## Changes

- Registers `packages/twenty-claude-skills` in the root Yarn workspace
list.
- Adds package metadata for `twenty-claude-skills`.
- Adds a README documenting the multi-skill layout.
- Adds the `twenty-record-presentation` skill under
`skills/twenty-record-presentation/SKILL.md`.

## Impact

This gives Claude-specific Twenty skills a dedicated package location
while preserving the skill metadata from the provided skill bundle.

## Validation

- Parsed the root `package.json` and
`packages/twenty-claude-skills/package.json` with Node.
- Compared the imported skill content against the source `.skill`
archive; the only difference is a trailing newline at EOF.
2026-05-11 14:56:45 +00:00
Paul RastoinandGitHub 0c5aec9c73 Ignore twenty versions constant files in prettier (#20448) 2026-05-11 14:23:21 +00:00
Abdul RahmanandGitHub ed75fc8a25 Use workflow inputSchema to render boolean, number, and enum fields in code/logic function steps (#20439)
<img width="415" height="772" alt="Screenshot 2026-05-11 at 4 44 08 PM"
src="https://github.com/user-attachments/assets/32dbdd3c-e60b-4c43-90bc-18be05f22dcf"
/>
<img width="414" height="371" alt="Screenshot 2026-05-11 at 4 48 24 PM"
src="https://github.com/user-attachments/assets/83be062c-7ed3-4953-98bb-e4290865040b"
/>
2026-05-11 14:21:08 +00:00
Paul RastoinandGitHub 9813467cee Refactor SAML relayState structure (#20430)
# Introduction
Restructure the RelayState and avoid asserting the idp identifier from
this opaque blob
Inferring the id from the secured validated and signed request params
2026-05-11 13:49:36 +00:00
1ea7c7ecc4 i18n - translations (#20449)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-05-11 16:03:20 +02:00
626455b534 chore(members): rename "Access" tab to "Invite" + fix e2e (#20447)
## Summary

Two things, both fallout from #20360:

1. Rename the `Members → Access` tab to `Members → Invite`. The previous
label leaned security-flavored; "Invite" reads as the verb users come
here to do.
2. Fix the `signup_invite_email` Playwright test (failing on main, e.g.
https://github.com/twentyhq/twenty/actions/runs/25671161586/job/75356474079).
The invite-link button moved off the default Team tab when the Members
page got tabbed; the test was looking for it on the wrong tab.

## Rename details

- File: `SettingsWorkspaceMembersAccessTab.tsx` →
`SettingsWorkspaceMembersInviteTab.tsx` (single git rename, ~99%
similarity)
- Exported component: `SettingsWorkspaceMembersAccessTab` →
`SettingsWorkspaceMembersInviteTab`
- Tab id (and URL hash): `access` → `invite`
- Tab title: `Access` → `Invite`
- Icon: `IconKey` → `IconUserPlus`
- Doc breadcrumbs (3 files): `Members → Access` → `Members → Invite`

## E2E fix

`MembersSection` (Page Object Model) now has an `inviteTab` locator (via
`getByTestId('tab-invite')`) and a `goToInviteTab()` helper. Both
`copyInviteLink` and `sendInviteEmail` click the Invite tab first, so
they work regardless of which tab the page lands on initially.
Idempotent if already there.

## Test plan

- [x] CI green (e2e test + lint + typecheck + format)
- Lingui `.po` files will pick up the new source paths on the next
translation pass — not touched here.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:54:34 +02:00
2c3e81960c chore: bump version to 2.5.0 (#20446)
## Summary

- Moves current version to previous versions array
- Sets TWENTY_CURRENT_VERSION to the new version
- Updates TWENTY_NEXT_VERSIONS with the next minor version

## Checklist

- [ ] Verify version constants are correct

---------

Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com>
Co-authored-by: prastoin <paul@twenty.com>
2026-05-11 15:53:34 +02:00
martmullandGitHub 487112d438 Upgrade sdk version (#20444)
from 2.3.0 to 2.3.1
2026-05-11 15:31:40 +02:00
5c1fe45760 fix: update broken AI documentation link (#20401)
## Summary

Updated the broken AI documentation link in
`AiChatApiKeyNotConfiguredMessage.tsx`.

## Changes

* Replaced outdated self-hosting AI docs URL
* Updated link to a valid self-hosting documentation page

Fixes #20071

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-05-11 15:29:37 +02:00
martmullandGitHub e72a907baa Stop rejecting application token on calendar and message events requests (#20440)
fixes https://github.com/twentyhq/twenty/issues/20423 by authorizing
application token to perform calendarEvents and message queries
2026-05-11 15:24:24 +02:00
8909badc59 i18n - website translations (#20434)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-05-11 14:15:28 +02:00
Abdullah.andGitHub c81019965d [Website] Extract HomeVisual into shared AppPreview section. (#20432) 2026-05-11 06:46:09 +02:00
58dd5d3561 i18n - docs translations (#20431)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-05-10 22:35:26 +02:00
c611a7ac20 i18n - docs translations (#20429)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-05-10 20:37:38 +02:00
50a4fe5040 i18n - translations (#20428)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-05-10 20:24:31 +02:00
34b927ff23 feat(public-domain): bind public domains to apps + reorganize settings (#20360)
## Summary

- **Public domains can now be bound to a specific app.** When a request
hits an app-bound public domain, route resolution restricts
logic-function matching to that app's HTTP-routed functions only —
isolating each app's routes to its own domain instead of letting routes
from other apps in the workspace match nondeterministically.
- **Settings sidebar reorganized.** Removed the standalone Domains page.
Workspace Domain → General. Approved Domains + Invitations → Members
"Access" tab. Emailing Domains + Public Domains → Apps "Developer" tab.
Roles → Members "Roles" tab.

## Why

The use case: someone building a partner portal app or a lead-collection
app declares private objects (leads, partners…) plus a few public HTTP
routes. Each app needs its own domain (`partners.acme.com`,
`leads.acme.com`) without those domains exposing every other app's
routes in the same workspace. Today's PublicDomainEntity is
workspace-scoped only, so all HTTP-routed logic functions in a workspace
compete for any public domain — first match wins nondeterministically.

## Backend

- Added nullable `applicationId` FK to `PublicDomainEntity`
(cascade-deleted with the app); indexed for the route-trigger lookup.
- New fast instance command
`2-4-instance-command-fast-1798000003000-add-application-id-to-public-domain`
adds the column, index, and FK constraint.
- `createPublicDomain(domain, applicationId)` accepts an optional app
binding; new `updatePublicDomain(domain, applicationId)` mutation
rebinds/unbinds an existing domain. Both validate the application
belongs to the workspace.
- `WorkspaceDomainsService.resolveWorkspaceAndPublicDomain(origin)`
returns both the workspace and the matched public domain in one query —
replacing the old back-to-back lookups in the route-trigger hot path.
`getWorkspaceByOriginOrDefaultWorkspace` is preserved as a thin wrapper.
- `RouteTriggerService` filters `logicFunction` by `applicationId` when
the matched public domain is app-scoped; falls back to workspace-wide
when unbound.
- Three sequential validation queries in `createPublicDomain` now run in
parallel via `Promise.all`.

## Frontend

| Old location | New location |
|---|---|
| Settings sidebar → Domains (standalone page) | Removed |
| Domains page → Workspace Domain | General page |
| Domains page → Approved Domains | Members → Access tab |
| Domains page → Emailing Domains | Apps → Developer tab |
| Domains page → Public Domains | Apps → Developer tab |
| Settings sidebar → Roles (standalone) | Members → Roles tab |
| `pages/settings/roles/` | `pages/settings/members/roles/` |

- The Public Domain detail page has an Application picker that uses
`Select`'s native `emptyOption` + `null` value pattern (matches
`SettingsDataModelObjectIdentifiersForm`).
- Members page tabs use the existing `TabListFromUrlOptionalEffect`
mechanism (rendered automatically by `TabList`) for hash-based tab
activation.
- `/settings/members/roles` redirects to `/settings/members#roles` so
role sub-pages' `navigate(SettingsPath.Roles)` lands on the Members page
with the Roles tab pre-selected.
- All affected breadcrumbs updated to nest under their new parents.
- `SettingsPath.Roles` and friends now nest under `members/`;
`Subdomain` and `CustomDomain` under `general/`; `PublicDomain` and
`EmailingDomain` under `applications/`.

## Test plan

- [x] `nx typecheck twenty-front` passes
- [x] `nx typecheck twenty-server` passes
- [x] `oxlint --type-aware` clean on all touched files
- [x] `prettier --check` clean on all touched files
- [x] Migration applied locally; `publicDomain.applicationId` (uuid,
nullable) confirmed in DB
- [x] GraphQL schema exposes `PublicDomain.applicationId`,
`createPublicDomain.applicationId`, `updatePublicDomain` mutation
- [x] **End-to-end route resolution scenarios verified locally:**
  - Domain bound to App A, function in App A → route matches 
- Domain bound to App B, function in App A → route does NOT match (HTTP
404 `TRIGGER_NOT_FOUND`) 
- Domain unbound (`applicationId = NULL`) → route matches workspace-wide

  - Unknown path on bound domain → returns 404 cleanly 
- [x] UI sanity (browser-tested at `apple.localhost:3001`):
  - General page shows Workspace Domain card
  - Members page shows Team / Access / Roles tabs
  - Access tab combines Invite by link + by email + Approved Domains
  - Roles tab embeds the role list
- `/settings/members/roles` direct URL → redirects + Roles tab
pre-selected
  - Apps Developer tab shows Emailing Domains + Public Domains sections
- Public Domain detail page has Application picker dropdown listing
workspace apps
- Sidebar nav: "Domains" and "Roles" no longer present (now folded into
General/Members)

## Notes for reviewers

- Creating a public domain via the UI still requires Cloudflare
credentials in the dev `.env` (`CLOUDFLARE_API_KEY`,
`CLOUDFLARE_PUBLIC_DOMAIN_ZONE_ID`, `PUBLIC_DOMAIN_URL`). The DNS step
is unchanged from main.
- The `applicationId` column is nullable, so existing public-domain rows
continue to work workspace-wide — no data backfill required.
- `SettingsRolesContainer` was deleted (no longer referenced after
`SettingsRoles` index page was removed).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 20:17:28 +02:00
620 changed files with 12743 additions and 5423 deletions
+38 -12
View File
@@ -164,9 +164,17 @@ jobs:
interval=5
elapsed=0
ADMIN_TOKEN=$(jq -r '.APPLE_JANE_ADMIN_ACCESS_TOKEN' packages/twenty-server/test/integration/constants/test-tokens.json)
while [ $elapsed -lt $timeout ]; do
if curl -s "http://localhost:${{ env.CURRENT_SERVER_PORT }}/graphql" > /dev/null 2>&1 && \
curl -s "http://localhost:${{ env.CURRENT_SERVER_PORT }}/rest/open-api/core" > /dev/null 2>&1; then
GRAPHQL_RESPONSE=$(curl -s -X POST "http://localhost:${{ env.CURRENT_SERVER_PORT }}/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-d '{"query":"{ __schema { queryType { name } } }"}' 2>/dev/null || echo '{}')
if echo "$GRAPHQL_RESPONSE" | jq -e '.data.__schema' > /dev/null 2>&1 && \
curl -fsS "http://localhost:${{ env.CURRENT_SERVER_PORT }}/rest/open-api/core" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" > /dev/null 2>&1; then
echo "Current branch server is ready!"
break
fi
@@ -177,10 +185,9 @@ jobs:
done
if [ $elapsed -ge $timeout ]; then
echo "Timeout waiting for current branch server to start"
echo "::warning::Timed out waiting for current branch server to serve a valid schema. Validation will skip the API diff."
echo "Current server log:"
cat /tmp/current-server.log || echo "No current server log found"
exit 1
fi
- name: Download GraphQL and REST responses from current branch
@@ -324,9 +331,17 @@ jobs:
interval=5
elapsed=0
ADMIN_TOKEN=$(jq -r '.APPLE_JANE_ADMIN_ACCESS_TOKEN' packages/twenty-server/test/integration/constants/test-tokens.json)
while [ $elapsed -lt $timeout ]; do
if curl -s "http://localhost:${{ env.MAIN_SERVER_PORT }}/graphql" > /dev/null 2>&1 && \
curl -s "http://localhost:${{ env.MAIN_SERVER_PORT }}/rest/open-api/core" > /dev/null 2>&1; then
GRAPHQL_RESPONSE=$(curl -s -X POST "http://localhost:${{ env.MAIN_SERVER_PORT }}/graphql" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-d '{"query":"{ __schema { queryType { name } } }"}' 2>/dev/null || echo '{}')
if echo "$GRAPHQL_RESPONSE" | jq -e '.data.__schema' > /dev/null 2>&1 && \
curl -fsS "http://localhost:${{ env.MAIN_SERVER_PORT }}/rest/open-api/core" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" > /dev/null 2>&1; then
echo "Main branch server is ready!"
break
fi
@@ -337,10 +352,9 @@ jobs:
done
if [ $elapsed -ge $timeout ]; then
echo "Timeout waiting for main branch server to start"
echo "::warning::Timed out waiting for main branch server to serve a valid schema. Validation will skip the API diff."
echo "Main server log:"
cat /tmp/main-server.log || echo "No main server log found"
exit 1
fi
- name: Download GraphQL and REST responses from main branch
@@ -407,11 +421,23 @@ jobs:
valid=true
for file in main-schema-introspection.json current-schema-introspection.json \
main-metadata-schema-introspection.json current-metadata-schema-introspection.json \
main-rest-api.json current-rest-api.json \
main-metadata-schema-introspection.json current-metadata-schema-introspection.json; do
if [ ! -f "$file" ]; then
echo "::warning::Missing GraphQL schema file: $file"
valid=false
elif ! jq -e '.data.__schema' "$file" >/dev/null 2>&1; then
echo "::warning::File $file is not a valid GraphQL introspection result. First 200 bytes: $(head -c 200 "$file")"
valid=false
fi
done
for file in main-rest-api.json current-rest-api.json \
main-rest-metadata-api.json current-rest-metadata-api.json; do
if [ ! -f "$file" ] || ! jq empty "$file" 2>/dev/null; then
echo "::warning::Invalid or missing schema file: $file"
if [ ! -f "$file" ]; then
echo "::warning::Missing OpenAPI spec file: $file"
valid=false
elif ! jq -e '.openapi // .swagger' "$file" >/dev/null 2>&1; then
echo "::warning::File $file is not a valid OpenAPI spec. First 200 bytes: $(head -c 200 "$file")"
valid=false
fi
done
+54 -7
View File
@@ -56,10 +56,54 @@ jobs:
- name: Create Tunnel
id: expose-tunnel
uses: codetalkio/expose-tunnel@v1.5.0
with:
service: bore.pub
port: 3000
env:
CLOUDFLARED_VERSION: '2026.3.0'
run: |
set -euo pipefail
# Install cloudflared (pinned for reproducibility)
sudo curl -fsSL -o /usr/local/bin/cloudflared \
"https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64"
sudo chmod +x /usr/local/bin/cloudflared
cloudflared --version
# Start an account-less "quick tunnel" pointing at the server container.
# Cloudflare prints the assigned https://*.trycloudflare.com URL into the log.
log_file="$RUNNER_TEMP/cloudflared.log"
: > "$log_file"
cloudflared tunnel \
--url http://localhost:3000 \
--no-autoupdate \
--logfile "$log_file" \
--loglevel info \
> "$RUNNER_TEMP/cloudflared.stdout" 2>&1 &
pid=$!
echo "$pid" > "$RUNNER_TEMP/cloudflared.pid"
echo "cloudflared PID: $pid"
# Wait up to 2 minutes for the URL to appear; fail fast if cloudflared exits.
url=''
for _ in $(seq 1 60); do
url=$(grep -oE 'https://[a-zA-Z0-9-]+\.trycloudflare\.com' "$log_file" 2>/dev/null | head -n1 || true)
[ -n "$url" ] && break
if ! kill -0 "$pid" 2>/dev/null; then
echo "cloudflared exited before producing a URL"
cat "$log_file" || true
exit 1
fi
sleep 2
done
if [ -z "$url" ]; then
echo "Timed out waiting for tunnel URL"
cat "$log_file" || true
exit 1
fi
echo "Tunnel URL: $url"
echo "tunnel-url=$url" >> "$GITHUB_OUTPUT"
- name: Start services with correct SERVER_URL
env:
@@ -99,9 +143,9 @@ jobs:
- name: Seed Dev Workspace
run: |
cd packages/twenty-docker/
echo "Seeding full dev workspace..."
if ! docker compose exec -T server yarn command:prod -- workspace:seed:dev; then
echo "❌ Seeding full dev workspace failed. Dumping server logs..."
echo "Seeding light dev workspace (Apple only)..."
if ! docker compose exec -T server yarn command:prod workspace:seed:dev --light; then
echo "❌ Seeding light dev workspace failed. Dumping server logs..."
docker compose logs server
exit 1
fi
@@ -134,6 +178,9 @@ jobs:
- name: Cleanup
if: always()
run: |
if [ -f "$RUNNER_TEMP/cloudflared.pid" ]; then
kill "$(cat "$RUNNER_TEMP/cloudflared.pid")" 2>/dev/null || true
fi
cd packages/twenty-docker/
docker compose down -v
working-directory: ./
+1
View File
@@ -57,6 +57,7 @@
"lint:diff-with-main": {
"executor": "nx:run-commands",
"cache": false,
"dependsOn": ["twenty-oxlint-rules:build"],
"options": {
"command": "FILES=$(git diff --name-only --diff-filter=d main -- {projectRoot}/ | grep -E '{args.pattern}'); [ -z \"$FILES\" ] && echo 'No changed files.' || (npx oxlint -c {projectRoot}/.oxlintrc.json $FILES && (prettier --check $FILES || (echo 'ERROR: Prettier formatting check failed! Fix with: npx nx lint:diff-with-main --configuration=fix' && false)))",
"pattern": "\\.(ts|tsx|js|jsx)$"
+2 -1
View File
@@ -63,7 +63,8 @@
"packages/twenty-cli",
"packages/create-twenty-app",
"packages/twenty-oxlint-rules",
"packages/twenty-companion"
"packages/twenty-companion",
"packages/twenty-claude-skills"
]
},
"prettier": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "create-twenty-app",
"version": "2.3.0",
"version": "2.3.1",
"description": "Command-line interface to create Twenty application",
"main": "dist/cli.cjs",
"bin": "dist/cli.cjs",
+9
View File
@@ -0,0 +1,9 @@
# twenty-claude-skills
Claude skills for working with Twenty.
Add skills under `skills/<skill-name>/SKILL.md`.
## Skills
- `twenty-record-presentation`: Retrieve and present Twenty CRM records as readable summaries or tables.
@@ -0,0 +1,10 @@
{
"name": "twenty-claude-skills",
"private": true,
"version": "0.1.0",
"description": "Claude skills for working with Twenty.",
"license": "AGPL-3.0",
"files": [
"skills"
]
}
@@ -0,0 +1,159 @@
---
name: twenty-record-presentation
description: "Retrieve and present Twenty CRM records as readable summaries or tables, using the connected Twenty MCP server to discover fields, fetch relevant data, format dates and values, build record links, and avoid raw API output."
---
# Twenty Record Presentation
## Overview
Retrieve the Twenty records needed to answer the user's question, then present them as a useful answer, not as raw API output. Always translate technical fields, timestamps, IDs, and nested structures into readable summaries that help the user scan, compare, and act.
## Retrieval Workflow
Use the selected connected Twenty MCP server when it is available
- `get_tool_catalog``learn_tools``execute_tool`
- Discover the relevant object, fields, filters, and sort options instead of guessing exact API names.
- Retrieve only the fields needed for the answer, plus the fields needed for ordering or disambiguation.
- For "latest", "most recent", or "recent" requests, include the relevant timestamp field used for sorting.
- If the user asks for a broad list, apply a practical limit and state how many records are shown.
- If required context is missing and cannot be discovered from the tools, ask one concise clarifying question.
- If no Twenty MCP tools are available, say that no callable Twenty MCP server is available in the current thread and ask the user to connect or expose the intended workspace.
## Response Shape
Start with the answer or count, then show the records in the clearest compact shape:
- For one record, use a labeled block.
- For 2 to 10 comparable records, use a Markdown table.
- For larger sets, show the most relevant rows first, mention the total, and offer the next useful filter or page only when needed.
- For nested records, summarize the important nested values instead of dumping JSON.
- When comparing records across workspaces, prefer one combined table with a Workspace column if it improves scanning. Use separate sections only when each workspace needs different columns.
Use English labels and prose. Keep user-provided names, record values, emails, URLs, and proper nouns unchanged.
## Record Links
Link records back to their original Twenty context whenever the workspace origin and record identity are known.
- Build record links with the Twenty show-page path: `/object/:objectNameSingular/:objectRecordId`.
- For absolute links, combine the workspace origin with that path, for example `https://example.twenty.com/object/person/record-id`.
- Use `recordReferences` from MCP responses when available to get `objectNameSingular`, `recordId`, and `displayName`.
- If `recordReferences` is missing, use the record's `id` and the object name from the tool that returned it.
- Prefer linking the record display name in tables and summaries instead of adding a raw ID column.
- When showing records from multiple workspaces, generate links with each record's own workspace origin.
- If the workspace origin is unknown, do not invent a hostname. Add a compact Record column with the object name and record ID, or say that direct links need the workspace URL.
## Dates and Times
Never expose ISO/RFC3339 timestamps as the main date display.
- Parse common technical formats such as `2026-05-05T09:43:18.123Z`, `2026-05-05T09:43:18+02:00`, Unix seconds, and Unix milliseconds.
- Convert instants with `Z` or an explicit offset to the user's timezone when known. If timezone is unknown, keep the source timezone or ask only when it changes the meaning.
- Preserve date-only values as dates. Do not shift date-only values across timezones.
- Display absolute dates. Use relative words such as "today", "yesterday", or "last week" only as a supplement when helpful.
- Include the year unless it is truly redundant in a small same-year table.
- Show seconds and milliseconds only when they matter for debugging, audit logs, or ordering events with near-identical times.
Examples, with user timezone Europe/Paris, UTC+2 in May:
- Timestamp: `2026-05-05T09:43:18.123Z` → May 5, 2026, 11:43 AM
- Date-only value: `2026-05-05` → May 5, 2026
If the exact raw timestamp is relevant, put it after the readable value:
- Created: May 5, 2026, 11:43 AM (raw: `2026-05-05T09:43:18.123Z`)
## Field Labels
Convert raw field names into user-facing labels:
- `createdAt` → Created
- `updatedAt` → Last updated
- `deletedAt` → Deleted
- `createdBy` → Created by
- `workspaceMemberId` → Workspace member
- `opportunityStage` → Opportunity stage
Prefer the label users see in Twenty when it is available from metadata. Otherwise, split camelCase, snake_case, and kebab-case into normal words.
## Value Formatting
Format values by meaning:
- **Empty or null**: Not set, or omit if the field is irrelevant.
- **Booleans**: Yes / No.
- **Money**: include currency and grouping, for example EUR 12,450 or USD 12,450 based on the record currency.
- **Percentages**: use `%`, round only enough to stay meaningful.
- **URLs and emails**: make them clickable Markdown links when useful.
- **IDs and UUIDs**: hide by default unless the user asks for identifiers, deduplication, debugging, or exact references.
- **Arrays**: show the count and the most important names, not the full serialized array.
## Record Ordering
When the user asks for "latest", "recent", or "last records":
- State which date field was used when it is not obvious, for example *sorted by Last updated*.
- Prefer `updatedAt` for "recent activity" and `createdAt` for "newest records" unless the user's wording or object semantics points to another date.
- Display the chosen date column in readable form.
- If multiple records share the same date, keep a deterministic secondary order such as name or ID.
## Table Alignment
Make tables easy to scan before making them visually decorative.
- Use Markdown alignment markers intentionally: text columns left-aligned (`:---`), numeric money/count columns right-aligned (`---:`), and short status columns centered only when that actually improves scanning (`:---:`).
- Keep record names on a stable left edge. If rows have favicons, use a dedicated narrow Icon column followed by a linked record-name column.
- If the table is compact and the image is known to be consistently small, it is acceptable to put `![alt](url) [Name](record-url)` in one cell. Do not also add emoji or extra symbols before the name.
- Keep fixed-format fields such as Created, Updated, Amount, and Source to the right of variable-width fields such as Name, Company, Person, and Domain.
- Use a consistent date format within a table so rows line up visually, for example *May 5, 2026, 11:43 AM* or *May 5, 11:43*.
- Prefer natural links over extra link columns: link the record name to Twenty, and link the domain or email only when that external destination is useful.
- Avoid raw ID columns in normal user-facing tables. IDs are long, visually dominant, and destroy alignment unless the user asks for them.
## Markdown Patterns
### Compact table
Use a compact table for comparable records:
```markdown
I found 5 recent opportunities, sorted by last updated date.
| Name | Stage | Amount | Last updated |
| :--- | :--- | ---: | :--- |
| [Acme renewal](https://example.twenty.com/object/opportunity/record-id-1) | Negotiation | EUR 12,450 | May 5, 2026, 11:43 AM |
| [Globex expansion](https://example.twenty.com/object/opportunity/record-id-2) | Discovery | EUR 8,000 | May 4, 2026, 4:10 PM |
```
### Labeled block
Use a labeled block for one important record:
```markdown
**[Acme renewal](https://example.twenty.com/object/opportunity/record-id-1)**
- Stage: Negotiation
- Amount: EUR 12,450
- Next action: Not set
- Last updated: May 5, 2026, 11:43 AM
```
## Raw Data Exceptions
Show raw JSON, raw timestamps, internal IDs, or full nested objects only when the user asks for debugging, export, exact API payloads, schema inspection, or reproducible commands. Even then, put a readable summary before the raw block.
Example:
> Acme renewal — Negotiation stage, EUR 12,450, last updated May 5, 2026, 11:43 AM. Full payload below:
>
> ```json
> {
> "id": "record-id-1",
> "name": "Acme renewal",
> "stage": "NEGOTIATION",
> "amountMicros": "12450000000",
> "currencyCode": "EUR",
> "updatedAt": "2026-05-05T09:43:18.123Z"
> }
> ```
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-client-sdk",
"version": "2.3.0",
"version": "2.3.1",
"sideEffects": false,
"license": "AGPL-3.0",
"scripts": {
@@ -932,6 +932,7 @@ type Workspace {
isMicrosoftAuthEnabled: Boolean!
isMicrosoftAuthBypassEnabled: Boolean!
isCustomDomainEnabled: Boolean!
isInternalMessagesImportEnabled: Boolean!
editableProfileFields: [String!]
defaultRole: Role
fastModel: String!
@@ -1747,17 +1748,13 @@ type FeatureFlag {
enum FeatureFlagKey {
IS_UNIQUE_INDEXES_ENABLED
IS_JSON_FILTER_ENABLED
IS_COMMAND_MENU_ITEM_ENABLED
IS_MARKETPLACE_SETTING_TAB_VISIBLE
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
IS_PUBLIC_DOMAIN_ENABLED
IS_EMAILING_DOMAIN_ENABLED
IS_EMAIL_GROUP_ENABLED
IS_JUNCTION_RELATIONS_ENABLED
IS_CONNECTED_ACCOUNT_MIGRATED
IS_RICH_TEXT_V1_MIGRATED
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED
IS_DATASOURCE_MIGRATED
IS_BILLING_V2_ENABLED
}
@@ -1970,76 +1967,6 @@ type RotateClientSecret {
clientSecret: String!
}
type ResendEmailVerificationToken {
success: Boolean!
}
type DeleteSso {
identityProviderId: UUID!
}
type EditSso {
id: UUID!
type: IdentityProviderType!
issuer: String!
name: String!
status: SSOIdentityProviderStatus!
}
type WorkspaceNameAndId {
displayName: String
id: UUID!
}
type FindAvailableSSOIDP {
type: IdentityProviderType!
id: UUID!
issuer: String!
name: String!
status: SSOIdentityProviderStatus!
workspace: WorkspaceNameAndId!
}
type SetupSso {
id: UUID!
type: IdentityProviderType!
issuer: String!
name: String!
status: SSOIdentityProviderStatus!
}
type SSOConnection {
type: IdentityProviderType!
id: UUID!
issuer: String!
name: String!
status: SSOIdentityProviderStatus!
}
type AvailableWorkspace {
id: UUID!
displayName: String
loginToken: String
personalInviteToken: String
inviteHash: String
workspaceUrls: WorkspaceUrls!
logo: String
sso: [SSOConnection!]!
}
type AvailableWorkspaces {
availableWorkspacesForSignIn: [AvailableWorkspace!]!
availableWorkspacesForSignUp: [AvailableWorkspace!]!
}
type DeletedWorkspaceMember {
id: UUID!
name: FullName!
userEmail: String!
avatarUrl: String
userWorkspaceId: UUID
}
type Relation {
type: RelationType!
sourceObjectMetadata: Object!
@@ -2161,6 +2088,76 @@ type FieldConnection {
edges: [FieldEdge!]!
}
type ResendEmailVerificationToken {
success: Boolean!
}
type DeleteSso {
identityProviderId: UUID!
}
type EditSso {
id: UUID!
type: IdentityProviderType!
issuer: String!
name: String!
status: SSOIdentityProviderStatus!
}
type WorkspaceNameAndId {
displayName: String
id: UUID!
}
type FindAvailableSSOIDP {
type: IdentityProviderType!
id: UUID!
issuer: String!
name: String!
status: SSOIdentityProviderStatus!
workspace: WorkspaceNameAndId!
}
type SetupSso {
id: UUID!
type: IdentityProviderType!
issuer: String!
name: String!
status: SSOIdentityProviderStatus!
}
type SSOConnection {
type: IdentityProviderType!
id: UUID!
issuer: String!
name: String!
status: SSOIdentityProviderStatus!
}
type AvailableWorkspace {
id: UUID!
displayName: String
loginToken: String
personalInviteToken: String
inviteHash: String
workspaceUrls: WorkspaceUrls!
logo: String
sso: [SSOConnection!]!
}
type AvailableWorkspaces {
availableWorkspacesForSignIn: [AvailableWorkspace!]!
availableWorkspacesForSignUp: [AvailableWorkspace!]!
}
type DeletedWorkspaceMember {
id: UUID!
name: FullName!
userEmail: String!
avatarUrl: String
userWorkspaceId: UUID
}
type BillingEntitlement {
key: BillingEntitlementKey!
value: Boolean!
@@ -2356,6 +2353,7 @@ type PublicDomain {
id: UUID!
domain: String!
isValidated: Boolean!
applicationId: UUID
createdAt: DateTime!
}
@@ -3327,7 +3325,8 @@ type Mutation {
updateLabPublicFeatureFlag(input: UpdateLabPublicFeatureFlagInput!): FeatureFlag!
enablePostgresProxy: PostgresCredentials!
disablePostgresProxy: PostgresCredentials!
createPublicDomain(domain: String!): PublicDomain!
createPublicDomain(domain: String!, applicationId: String): PublicDomain!
updatePublicDomain(domain: String!, applicationId: String): PublicDomain!
deletePublicDomain(domain: String!): Boolean!
checkPublicDomainValidRecords(domain: String!): DomainValidRecords
createEmailingDomain(domain: String!, driver: EmailingDomainDriver!): EmailingDomain!
@@ -4316,6 +4315,7 @@ input UpdateWorkspaceInput {
editableProfileFields: [String!]
enabledAiModelIds: [String!]
useRecommendedModels: Boolean
isInternalMessagesImportEnabled: Boolean
}
input WorkspaceMigrationInput {
@@ -652,6 +652,7 @@ export interface Workspace {
isMicrosoftAuthEnabled: Scalars['Boolean']
isMicrosoftAuthBypassEnabled: Scalars['Boolean']
isCustomDomainEnabled: Scalars['Boolean']
isInternalMessagesImportEnabled: Scalars['Boolean']
editableProfileFields?: Scalars['String'][]
defaultRole?: Role
fastModel: Scalars['String']
@@ -1388,7 +1389,7 @@ export interface FeatureFlag {
__typename: 'FeatureFlag'
}
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_DATASOURCE_MIGRATED' | 'IS_BILLING_V2_ENABLED'
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_BILLING_V2_ENABLED'
export interface WorkspaceUrls {
customUrl?: Scalars['String']
@@ -1604,86 +1605,6 @@ export interface RotateClientSecret {
__typename: 'RotateClientSecret'
}
export interface ResendEmailVerificationToken {
success: Scalars['Boolean']
__typename: 'ResendEmailVerificationToken'
}
export interface DeleteSso {
identityProviderId: Scalars['UUID']
__typename: 'DeleteSso'
}
export interface EditSso {
id: Scalars['UUID']
type: IdentityProviderType
issuer: Scalars['String']
name: Scalars['String']
status: SSOIdentityProviderStatus
__typename: 'EditSso'
}
export interface WorkspaceNameAndId {
displayName?: Scalars['String']
id: Scalars['UUID']
__typename: 'WorkspaceNameAndId'
}
export interface FindAvailableSSOIDP {
type: IdentityProviderType
id: Scalars['UUID']
issuer: Scalars['String']
name: Scalars['String']
status: SSOIdentityProviderStatus
workspace: WorkspaceNameAndId
__typename: 'FindAvailableSSOIDP'
}
export interface SetupSso {
id: Scalars['UUID']
type: IdentityProviderType
issuer: Scalars['String']
name: Scalars['String']
status: SSOIdentityProviderStatus
__typename: 'SetupSso'
}
export interface SSOConnection {
type: IdentityProviderType
id: Scalars['UUID']
issuer: Scalars['String']
name: Scalars['String']
status: SSOIdentityProviderStatus
__typename: 'SSOConnection'
}
export interface AvailableWorkspace {
id: Scalars['UUID']
displayName?: Scalars['String']
loginToken?: Scalars['String']
personalInviteToken?: Scalars['String']
inviteHash?: Scalars['String']
workspaceUrls: WorkspaceUrls
logo?: Scalars['String']
sso: SSOConnection[]
__typename: 'AvailableWorkspace'
}
export interface AvailableWorkspaces {
availableWorkspacesForSignIn: AvailableWorkspace[]
availableWorkspacesForSignUp: AvailableWorkspace[]
__typename: 'AvailableWorkspaces'
}
export interface DeletedWorkspaceMember {
id: Scalars['UUID']
name: FullName
userEmail: Scalars['String']
avatarUrl?: Scalars['String']
userWorkspaceId?: Scalars['UUID']
__typename: 'DeletedWorkspaceMember'
}
export interface Relation {
type: RelationType
sourceObjectMetadata: Object
@@ -1803,6 +1724,86 @@ export interface FieldConnection {
__typename: 'FieldConnection'
}
export interface ResendEmailVerificationToken {
success: Scalars['Boolean']
__typename: 'ResendEmailVerificationToken'
}
export interface DeleteSso {
identityProviderId: Scalars['UUID']
__typename: 'DeleteSso'
}
export interface EditSso {
id: Scalars['UUID']
type: IdentityProviderType
issuer: Scalars['String']
name: Scalars['String']
status: SSOIdentityProviderStatus
__typename: 'EditSso'
}
export interface WorkspaceNameAndId {
displayName?: Scalars['String']
id: Scalars['UUID']
__typename: 'WorkspaceNameAndId'
}
export interface FindAvailableSSOIDP {
type: IdentityProviderType
id: Scalars['UUID']
issuer: Scalars['String']
name: Scalars['String']
status: SSOIdentityProviderStatus
workspace: WorkspaceNameAndId
__typename: 'FindAvailableSSOIDP'
}
export interface SetupSso {
id: Scalars['UUID']
type: IdentityProviderType
issuer: Scalars['String']
name: Scalars['String']
status: SSOIdentityProviderStatus
__typename: 'SetupSso'
}
export interface SSOConnection {
type: IdentityProviderType
id: Scalars['UUID']
issuer: Scalars['String']
name: Scalars['String']
status: SSOIdentityProviderStatus
__typename: 'SSOConnection'
}
export interface AvailableWorkspace {
id: Scalars['UUID']
displayName?: Scalars['String']
loginToken?: Scalars['String']
personalInviteToken?: Scalars['String']
inviteHash?: Scalars['String']
workspaceUrls: WorkspaceUrls
logo?: Scalars['String']
sso: SSOConnection[]
__typename: 'AvailableWorkspace'
}
export interface AvailableWorkspaces {
availableWorkspacesForSignIn: AvailableWorkspace[]
availableWorkspacesForSignUp: AvailableWorkspace[]
__typename: 'AvailableWorkspaces'
}
export interface DeletedWorkspaceMember {
id: Scalars['UUID']
name: FullName
userEmail: Scalars['String']
avatarUrl?: Scalars['String']
userWorkspaceId?: Scalars['UUID']
__typename: 'DeletedWorkspaceMember'
}
export interface BillingEntitlement {
key: BillingEntitlementKey
value: Scalars['Boolean']
@@ -2026,6 +2027,7 @@ export interface PublicDomain {
id: Scalars['UUID']
domain: Scalars['String']
isValidated: Scalars['Boolean']
applicationId?: Scalars['UUID']
createdAt: Scalars['DateTime']
__typename: 'PublicDomain'
}
@@ -2856,6 +2858,7 @@ export interface Mutation {
enablePostgresProxy: PostgresCredentials
disablePostgresProxy: PostgresCredentials
createPublicDomain: PublicDomain
updatePublicDomain: PublicDomain
deletePublicDomain: Scalars['Boolean']
checkPublicDomainValidRecords?: DomainValidRecords
createEmailingDomain: EmailingDomain
@@ -3564,6 +3567,7 @@ export interface WorkspaceGenqlSelection{
isMicrosoftAuthEnabled?: boolean | number
isMicrosoftAuthBypassEnabled?: boolean | number
isCustomDomainEnabled?: boolean | number
isInternalMessagesImportEnabled?: boolean | number
editableProfileFields?: boolean | number
defaultRole?: RoleGenqlSelection
fastModel?: boolean | number
@@ -4562,96 +4566,6 @@ export interface RotateClientSecretGenqlSelection{
__scalar?: boolean | number
}
export interface ResendEmailVerificationTokenGenqlSelection{
success?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface DeleteSsoGenqlSelection{
identityProviderId?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface EditSsoGenqlSelection{
id?: boolean | number
type?: boolean | number
issuer?: boolean | number
name?: boolean | number
status?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface WorkspaceNameAndIdGenqlSelection{
displayName?: boolean | number
id?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface FindAvailableSSOIDPGenqlSelection{
type?: boolean | number
id?: boolean | number
issuer?: boolean | number
name?: boolean | number
status?: boolean | number
workspace?: WorkspaceNameAndIdGenqlSelection
__typename?: boolean | number
__scalar?: boolean | number
}
export interface SetupSsoGenqlSelection{
id?: boolean | number
type?: boolean | number
issuer?: boolean | number
name?: boolean | number
status?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface SSOConnectionGenqlSelection{
type?: boolean | number
id?: boolean | number
issuer?: boolean | number
name?: boolean | number
status?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface AvailableWorkspaceGenqlSelection{
id?: boolean | number
displayName?: boolean | number
loginToken?: boolean | number
personalInviteToken?: boolean | number
inviteHash?: boolean | number
workspaceUrls?: WorkspaceUrlsGenqlSelection
logo?: boolean | number
sso?: SSOConnectionGenqlSelection
__typename?: boolean | number
__scalar?: boolean | number
}
export interface AvailableWorkspacesGenqlSelection{
availableWorkspacesForSignIn?: AvailableWorkspaceGenqlSelection
availableWorkspacesForSignUp?: AvailableWorkspaceGenqlSelection
__typename?: boolean | number
__scalar?: boolean | number
}
export interface DeletedWorkspaceMemberGenqlSelection{
id?: boolean | number
name?: FullNameGenqlSelection
userEmail?: boolean | number
avatarUrl?: boolean | number
userWorkspaceId?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface RelationGenqlSelection{
type?: boolean | number
sourceObjectMetadata?: ObjectGenqlSelection
@@ -4781,6 +4695,96 @@ export interface FieldConnectionGenqlSelection{
__scalar?: boolean | number
}
export interface ResendEmailVerificationTokenGenqlSelection{
success?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface DeleteSsoGenqlSelection{
identityProviderId?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface EditSsoGenqlSelection{
id?: boolean | number
type?: boolean | number
issuer?: boolean | number
name?: boolean | number
status?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface WorkspaceNameAndIdGenqlSelection{
displayName?: boolean | number
id?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface FindAvailableSSOIDPGenqlSelection{
type?: boolean | number
id?: boolean | number
issuer?: boolean | number
name?: boolean | number
status?: boolean | number
workspace?: WorkspaceNameAndIdGenqlSelection
__typename?: boolean | number
__scalar?: boolean | number
}
export interface SetupSsoGenqlSelection{
id?: boolean | number
type?: boolean | number
issuer?: boolean | number
name?: boolean | number
status?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface SSOConnectionGenqlSelection{
type?: boolean | number
id?: boolean | number
issuer?: boolean | number
name?: boolean | number
status?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface AvailableWorkspaceGenqlSelection{
id?: boolean | number
displayName?: boolean | number
loginToken?: boolean | number
personalInviteToken?: boolean | number
inviteHash?: boolean | number
workspaceUrls?: WorkspaceUrlsGenqlSelection
logo?: boolean | number
sso?: SSOConnectionGenqlSelection
__typename?: boolean | number
__scalar?: boolean | number
}
export interface AvailableWorkspacesGenqlSelection{
availableWorkspacesForSignIn?: AvailableWorkspaceGenqlSelection
availableWorkspacesForSignUp?: AvailableWorkspaceGenqlSelection
__typename?: boolean | number
__scalar?: boolean | number
}
export interface DeletedWorkspaceMemberGenqlSelection{
id?: boolean | number
name?: FullNameGenqlSelection
userEmail?: boolean | number
avatarUrl?: boolean | number
userWorkspaceId?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface BillingEntitlementGenqlSelection{
key?: boolean | number
value?: boolean | number
@@ -5035,6 +5039,7 @@ export interface PublicDomainGenqlSelection{
id?: boolean | number
domain?: boolean | number
isValidated?: boolean | number
applicationId?: boolean | number
createdAt?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
@@ -5922,7 +5927,8 @@ export interface MutationGenqlSelection{
updateLabPublicFeatureFlag?: (FeatureFlagGenqlSelection & { __args: {input: UpdateLabPublicFeatureFlagInput} })
enablePostgresProxy?: PostgresCredentialsGenqlSelection
disablePostgresProxy?: PostgresCredentialsGenqlSelection
createPublicDomain?: (PublicDomainGenqlSelection & { __args: {domain: Scalars['String']} })
createPublicDomain?: (PublicDomainGenqlSelection & { __args: {domain: Scalars['String'], applicationId?: (Scalars['String'] | null)} })
updatePublicDomain?: (PublicDomainGenqlSelection & { __args: {domain: Scalars['String'], applicationId?: (Scalars['String'] | null)} })
deletePublicDomain?: { __args: {domain: Scalars['String']} }
checkPublicDomainValidRecords?: (DomainValidRecordsGenqlSelection & { __args: {domain: Scalars['String']} })
createEmailingDomain?: (EmailingDomainGenqlSelection & { __args: {domain: Scalars['String'], driver: EmailingDomainDriver} })
@@ -6265,7 +6271,7 @@ export interface UpdateWorkspaceMemberSettingsInput {workspaceMemberId: Scalars[
export interface ActivateWorkspaceInput {displayName?: (Scalars['String'] | null)}
export interface UpdateWorkspaceInput {subdomain?: (Scalars['String'] | null),customDomain?: (Scalars['String'] | null),displayName?: (Scalars['String'] | null),logo?: (Scalars['String'] | null),inviteHash?: (Scalars['String'] | null),isPublicInviteLinkEnabled?: (Scalars['Boolean'] | null),allowImpersonation?: (Scalars['Boolean'] | null),isGoogleAuthEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthEnabled?: (Scalars['Boolean'] | null),isPasswordAuthEnabled?: (Scalars['Boolean'] | null),isGoogleAuthBypassEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthBypassEnabled?: (Scalars['Boolean'] | null),isPasswordAuthBypassEnabled?: (Scalars['Boolean'] | null),defaultRoleId?: (Scalars['UUID'] | null),isTwoFactorAuthenticationEnforced?: (Scalars['Boolean'] | null),trashRetentionDays?: (Scalars['Float'] | null),eventLogRetentionDays?: (Scalars['Float'] | null),fastModel?: (Scalars['String'] | null),smartModel?: (Scalars['String'] | null),aiAdditionalInstructions?: (Scalars['String'] | null),editableProfileFields?: (Scalars['String'][] | null),enabledAiModelIds?: (Scalars['String'][] | null),useRecommendedModels?: (Scalars['Boolean'] | null)}
export interface UpdateWorkspaceInput {subdomain?: (Scalars['String'] | null),customDomain?: (Scalars['String'] | null),displayName?: (Scalars['String'] | null),logo?: (Scalars['String'] | null),inviteHash?: (Scalars['String'] | null),isPublicInviteLinkEnabled?: (Scalars['Boolean'] | null),allowImpersonation?: (Scalars['Boolean'] | null),isGoogleAuthEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthEnabled?: (Scalars['Boolean'] | null),isPasswordAuthEnabled?: (Scalars['Boolean'] | null),isGoogleAuthBypassEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthBypassEnabled?: (Scalars['Boolean'] | null),isPasswordAuthBypassEnabled?: (Scalars['Boolean'] | null),defaultRoleId?: (Scalars['UUID'] | null),isTwoFactorAuthenticationEnforced?: (Scalars['Boolean'] | null),trashRetentionDays?: (Scalars['Float'] | null),eventLogRetentionDays?: (Scalars['Float'] | null),fastModel?: (Scalars['String'] | null),smartModel?: (Scalars['String'] | null),aiAdditionalInstructions?: (Scalars['String'] | null),editableProfileFields?: (Scalars['String'][] | null),enabledAiModelIds?: (Scalars['String'][] | null),useRecommendedModels?: (Scalars['Boolean'] | null),isInternalMessagesImportEnabled?: (Scalars['Boolean'] | null)}
export interface WorkspaceMigrationInput {actions: WorkspaceMigrationDeleteActionInput[]}
@@ -7394,86 +7400,6 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
const ResendEmailVerificationToken_possibleTypes: string[] = ['ResendEmailVerificationToken']
export const isResendEmailVerificationToken = (obj?: { __typename?: any } | null): obj is ResendEmailVerificationToken => {
if (!obj?.__typename) throw new Error('__typename is missing in "isResendEmailVerificationToken"')
return ResendEmailVerificationToken_possibleTypes.includes(obj.__typename)
}
const DeleteSso_possibleTypes: string[] = ['DeleteSso']
export const isDeleteSso = (obj?: { __typename?: any } | null): obj is DeleteSso => {
if (!obj?.__typename) throw new Error('__typename is missing in "isDeleteSso"')
return DeleteSso_possibleTypes.includes(obj.__typename)
}
const EditSso_possibleTypes: string[] = ['EditSso']
export const isEditSso = (obj?: { __typename?: any } | null): obj is EditSso => {
if (!obj?.__typename) throw new Error('__typename is missing in "isEditSso"')
return EditSso_possibleTypes.includes(obj.__typename)
}
const WorkspaceNameAndId_possibleTypes: string[] = ['WorkspaceNameAndId']
export const isWorkspaceNameAndId = (obj?: { __typename?: any } | null): obj is WorkspaceNameAndId => {
if (!obj?.__typename) throw new Error('__typename is missing in "isWorkspaceNameAndId"')
return WorkspaceNameAndId_possibleTypes.includes(obj.__typename)
}
const FindAvailableSSOIDP_possibleTypes: string[] = ['FindAvailableSSOIDP']
export const isFindAvailableSSOIDP = (obj?: { __typename?: any } | null): obj is FindAvailableSSOIDP => {
if (!obj?.__typename) throw new Error('__typename is missing in "isFindAvailableSSOIDP"')
return FindAvailableSSOIDP_possibleTypes.includes(obj.__typename)
}
const SetupSso_possibleTypes: string[] = ['SetupSso']
export const isSetupSso = (obj?: { __typename?: any } | null): obj is SetupSso => {
if (!obj?.__typename) throw new Error('__typename is missing in "isSetupSso"')
return SetupSso_possibleTypes.includes(obj.__typename)
}
const SSOConnection_possibleTypes: string[] = ['SSOConnection']
export const isSSOConnection = (obj?: { __typename?: any } | null): obj is SSOConnection => {
if (!obj?.__typename) throw new Error('__typename is missing in "isSSOConnection"')
return SSOConnection_possibleTypes.includes(obj.__typename)
}
const AvailableWorkspace_possibleTypes: string[] = ['AvailableWorkspace']
export const isAvailableWorkspace = (obj?: { __typename?: any } | null): obj is AvailableWorkspace => {
if (!obj?.__typename) throw new Error('__typename is missing in "isAvailableWorkspace"')
return AvailableWorkspace_possibleTypes.includes(obj.__typename)
}
const AvailableWorkspaces_possibleTypes: string[] = ['AvailableWorkspaces']
export const isAvailableWorkspaces = (obj?: { __typename?: any } | null): obj is AvailableWorkspaces => {
if (!obj?.__typename) throw new Error('__typename is missing in "isAvailableWorkspaces"')
return AvailableWorkspaces_possibleTypes.includes(obj.__typename)
}
const DeletedWorkspaceMember_possibleTypes: string[] = ['DeletedWorkspaceMember']
export const isDeletedWorkspaceMember = (obj?: { __typename?: any } | null): obj is DeletedWorkspaceMember => {
if (!obj?.__typename) throw new Error('__typename is missing in "isDeletedWorkspaceMember"')
return DeletedWorkspaceMember_possibleTypes.includes(obj.__typename)
}
const Relation_possibleTypes: string[] = ['Relation']
export const isRelation = (obj?: { __typename?: any } | null): obj is Relation => {
if (!obj?.__typename) throw new Error('__typename is missing in "isRelation"')
@@ -7586,6 +7512,86 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
const ResendEmailVerificationToken_possibleTypes: string[] = ['ResendEmailVerificationToken']
export const isResendEmailVerificationToken = (obj?: { __typename?: any } | null): obj is ResendEmailVerificationToken => {
if (!obj?.__typename) throw new Error('__typename is missing in "isResendEmailVerificationToken"')
return ResendEmailVerificationToken_possibleTypes.includes(obj.__typename)
}
const DeleteSso_possibleTypes: string[] = ['DeleteSso']
export const isDeleteSso = (obj?: { __typename?: any } | null): obj is DeleteSso => {
if (!obj?.__typename) throw new Error('__typename is missing in "isDeleteSso"')
return DeleteSso_possibleTypes.includes(obj.__typename)
}
const EditSso_possibleTypes: string[] = ['EditSso']
export const isEditSso = (obj?: { __typename?: any } | null): obj is EditSso => {
if (!obj?.__typename) throw new Error('__typename is missing in "isEditSso"')
return EditSso_possibleTypes.includes(obj.__typename)
}
const WorkspaceNameAndId_possibleTypes: string[] = ['WorkspaceNameAndId']
export const isWorkspaceNameAndId = (obj?: { __typename?: any } | null): obj is WorkspaceNameAndId => {
if (!obj?.__typename) throw new Error('__typename is missing in "isWorkspaceNameAndId"')
return WorkspaceNameAndId_possibleTypes.includes(obj.__typename)
}
const FindAvailableSSOIDP_possibleTypes: string[] = ['FindAvailableSSOIDP']
export const isFindAvailableSSOIDP = (obj?: { __typename?: any } | null): obj is FindAvailableSSOIDP => {
if (!obj?.__typename) throw new Error('__typename is missing in "isFindAvailableSSOIDP"')
return FindAvailableSSOIDP_possibleTypes.includes(obj.__typename)
}
const SetupSso_possibleTypes: string[] = ['SetupSso']
export const isSetupSso = (obj?: { __typename?: any } | null): obj is SetupSso => {
if (!obj?.__typename) throw new Error('__typename is missing in "isSetupSso"')
return SetupSso_possibleTypes.includes(obj.__typename)
}
const SSOConnection_possibleTypes: string[] = ['SSOConnection']
export const isSSOConnection = (obj?: { __typename?: any } | null): obj is SSOConnection => {
if (!obj?.__typename) throw new Error('__typename is missing in "isSSOConnection"')
return SSOConnection_possibleTypes.includes(obj.__typename)
}
const AvailableWorkspace_possibleTypes: string[] = ['AvailableWorkspace']
export const isAvailableWorkspace = (obj?: { __typename?: any } | null): obj is AvailableWorkspace => {
if (!obj?.__typename) throw new Error('__typename is missing in "isAvailableWorkspace"')
return AvailableWorkspace_possibleTypes.includes(obj.__typename)
}
const AvailableWorkspaces_possibleTypes: string[] = ['AvailableWorkspaces']
export const isAvailableWorkspaces = (obj?: { __typename?: any } | null): obj is AvailableWorkspaces => {
if (!obj?.__typename) throw new Error('__typename is missing in "isAvailableWorkspaces"')
return AvailableWorkspaces_possibleTypes.includes(obj.__typename)
}
const DeletedWorkspaceMember_possibleTypes: string[] = ['DeletedWorkspaceMember']
export const isDeletedWorkspaceMember = (obj?: { __typename?: any } | null): obj is DeletedWorkspaceMember => {
if (!obj?.__typename) throw new Error('__typename is missing in "isDeletedWorkspaceMember"')
return DeletedWorkspaceMember_possibleTypes.includes(obj.__typename)
}
const BillingEntitlement_possibleTypes: string[] = ['BillingEntitlement']
export const isBillingEntitlement = (obj?: { __typename?: any } | null): obj is BillingEntitlement => {
if (!obj?.__typename) throw new Error('__typename is missing in "isBillingEntitlement"')
@@ -8717,17 +8723,13 @@ export const enumLogicFunctionExecutionStatus = {
export const enumFeatureFlagKey = {
IS_UNIQUE_INDEXES_ENABLED: 'IS_UNIQUE_INDEXES_ENABLED' as const,
IS_JSON_FILTER_ENABLED: 'IS_JSON_FILTER_ENABLED' as const,
IS_COMMAND_MENU_ITEM_ENABLED: 'IS_COMMAND_MENU_ITEM_ENABLED' as const,
IS_MARKETPLACE_SETTING_TAB_VISIBLE: 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' as const,
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as const,
IS_PUBLIC_DOMAIN_ENABLED: 'IS_PUBLIC_DOMAIN_ENABLED' as const,
IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const,
IS_EMAIL_GROUP_ENABLED: 'IS_EMAIL_GROUP_ENABLED' as const,
IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const,
IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' as const,
IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const,
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const,
IS_DATASOURCE_MIGRATED: 'IS_DATASOURCE_MIGRATED' as const,
IS_BILLING_V2_ENABLED: 'IS_BILLING_V2_ENABLED' as const
}
@@ -56,7 +56,7 @@ export default {
181,
184,
187,
210,
200,
225,
261,
262,
@@ -946,10 +946,10 @@ export default {
3
],
"relation": [
209
199
],
"morphRelations": [
209
199
],
"object": [
55
@@ -1008,7 +1008,7 @@ export default {
45
],
"objectMetadata": [
217,
207,
{
"paging": [
48,
@@ -1021,7 +1021,7 @@ export default {
}
],
"indexFieldMetadatas": [
215,
205,
{
"paging": [
48,
@@ -1266,7 +1266,7 @@ export default {
46
],
"fields": [
222,
212,
{
"paging": [
48,
@@ -1279,7 +1279,7 @@ export default {
}
],
"indexMetadatas": [
220,
210,
{
"paging": [
48,
@@ -1835,6 +1835,9 @@ export default {
"isCustomDomainEnabled": [
6
],
"isInternalMessagesImportEnabled": [
6
],
"editableProfileFields": [
1
],
@@ -1976,7 +1979,7 @@ export default {
20
],
"deletedWorkspaceMembers": [
208
223
],
"hasPassword": [
6
@@ -1988,7 +1991,7 @@ export default {
17
],
"availableWorkspaces": [
207
222
],
"__typename": [
1
@@ -3857,6 +3860,176 @@ export default {
1
]
},
"Relation": {
"type": [
200
],
"sourceObjectMetadata": [
55
],
"targetObjectMetadata": [
55
],
"sourceFieldMetadata": [
43
],
"targetFieldMetadata": [
43
],
"__typename": [
1
]
},
"RelationType": {},
"IndexEdge": {
"node": [
46
],
"cursor": [
49
],
"__typename": [
1
]
},
"PageInfo": {
"hasNextPage": [
6
],
"hasPreviousPage": [
6
],
"startCursor": [
49
],
"endCursor": [
49
],
"__typename": [
1
]
},
"IndexConnection": {
"pageInfo": [
202
],
"edges": [
201
],
"__typename": [
1
]
},
"IndexFieldEdge": {
"node": [
45
],
"cursor": [
49
],
"__typename": [
1
]
},
"IndexIndexFieldMetadatasConnection": {
"pageInfo": [
202
],
"edges": [
204
],
"__typename": [
1
]
},
"ObjectEdge": {
"node": [
55
],
"cursor": [
49
],
"__typename": [
1
]
},
"IndexObjectMetadataConnection": {
"pageInfo": [
202
],
"edges": [
206
],
"__typename": [
1
]
},
"ObjectRecordCount": {
"objectNamePlural": [
1
],
"totalCount": [
21
],
"__typename": [
1
]
},
"ObjectConnection": {
"pageInfo": [
202
],
"edges": [
206
],
"__typename": [
1
]
},
"ObjectIndexMetadatasConnection": {
"pageInfo": [
202
],
"edges": [
201
],
"__typename": [
1
]
},
"FieldEdge": {
"node": [
43
],
"cursor": [
49
],
"__typename": [
1
]
},
"ObjectFieldsConnection": {
"pageInfo": [
202
],
"edges": [
211
],
"__typename": [
1
]
},
"FieldConnection": {
"pageInfo": [
202
],
"edges": [
211
],
"__typename": [
1
]
},
"ResendEmailVerificationToken": {
"success": [
6
@@ -3921,7 +4094,7 @@ export default {
174
],
"workspace": [
202
217
],
"__typename": [
1
@@ -3990,7 +4163,7 @@ export default {
1
],
"sso": [
205
220
],
"__typename": [
1
@@ -3998,10 +4171,10 @@ export default {
},
"AvailableWorkspaces": {
"availableWorkspacesForSignIn": [
206
221
],
"availableWorkspacesForSignUp": [
206
221
],
"__typename": [
1
@@ -4027,176 +4200,6 @@ export default {
1
]
},
"Relation": {
"type": [
210
],
"sourceObjectMetadata": [
55
],
"targetObjectMetadata": [
55
],
"sourceFieldMetadata": [
43
],
"targetFieldMetadata": [
43
],
"__typename": [
1
]
},
"RelationType": {},
"IndexEdge": {
"node": [
46
],
"cursor": [
49
],
"__typename": [
1
]
},
"PageInfo": {
"hasNextPage": [
6
],
"hasPreviousPage": [
6
],
"startCursor": [
49
],
"endCursor": [
49
],
"__typename": [
1
]
},
"IndexConnection": {
"pageInfo": [
212
],
"edges": [
211
],
"__typename": [
1
]
},
"IndexFieldEdge": {
"node": [
45
],
"cursor": [
49
],
"__typename": [
1
]
},
"IndexIndexFieldMetadatasConnection": {
"pageInfo": [
212
],
"edges": [
214
],
"__typename": [
1
]
},
"ObjectEdge": {
"node": [
55
],
"cursor": [
49
],
"__typename": [
1
]
},
"IndexObjectMetadataConnection": {
"pageInfo": [
212
],
"edges": [
216
],
"__typename": [
1
]
},
"ObjectRecordCount": {
"objectNamePlural": [
1
],
"totalCount": [
21
],
"__typename": [
1
]
},
"ObjectConnection": {
"pageInfo": [
212
],
"edges": [
216
],
"__typename": [
1
]
},
"ObjectIndexMetadatasConnection": {
"pageInfo": [
212
],
"edges": [
211
],
"__typename": [
1
]
},
"FieldEdge": {
"node": [
43
],
"cursor": [
49
],
"__typename": [
1
]
},
"ObjectFieldsConnection": {
"pageInfo": [
212
],
"edges": [
221
],
"__typename": [
1
]
},
"FieldConnection": {
"pageInfo": [
212
],
"edges": [
221
],
"__typename": [
1
]
},
"BillingEntitlement": {
"key": [
225
@@ -4310,7 +4313,7 @@ export default {
234
],
"availableWorkspaces": [
207
222
],
"__typename": [
1
@@ -4616,6 +4619,9 @@ export default {
"isValidated": [
6
],
"applicationId": [
3
],
"createdAt": [
4
],
@@ -6068,7 +6074,7 @@ export default {
}
],
"objectRecordCounts": [
218
208
],
"object": [
55,
@@ -6080,7 +6086,7 @@ export default {
}
],
"objects": [
219,
209,
{
"paging": [
48,
@@ -6102,7 +6108,7 @@ export default {
}
],
"indexMetadatas": [
213,
203,
{
"paging": [
48,
@@ -6151,7 +6157,7 @@ export default {
}
],
"fields": [
223,
213,
{
"paging": [
48,
@@ -6422,7 +6428,7 @@ export default {
}
],
"getSSOIdentityProviders": [
203
218
],
"eventLogs": [
289,
@@ -8390,7 +8396,7 @@ export default {
}
],
"resendEmailVerificationToken": [
199,
214,
{
"email": [
1,
@@ -8457,7 +8463,7 @@ export default {
}
],
"createOIDCIdentityProvider": [
204,
219,
{
"input": [
455,
@@ -8466,7 +8472,7 @@ export default {
}
],
"createSAMLIdentityProvider": [
204,
219,
{
"input": [
456,
@@ -8475,7 +8481,7 @@ export default {
}
],
"deleteSSOIdentityProvider": [
200,
215,
{
"input": [
457,
@@ -8484,7 +8490,7 @@ export default {
}
],
"editSSOIdentityProvider": [
201,
216,
{
"input": [
458,
@@ -8573,6 +8579,21 @@ export default {
"domain": [
1,
"String!"
],
"applicationId": [
1
]
}
],
"updatePublicDomain": [
258,
{
"domain": [
1,
"String!"
],
"applicationId": [
1
]
}
],
@@ -10934,6 +10955,9 @@ export default {
"useRecommendedModels": [
6
],
"isInternalMessagesImportEnabled": [
6
],
"__typename": [
1
]
@@ -37,7 +37,7 @@ Both are available as REST and GraphQL. GraphQL adds batch upserts and the abili
Authorization: Bearer YOUR_API_KEY
```
Create an API key in **Settings → API & Webhooks → + Create key**. Copy it immediately — it's shown once. Keys can be scoped to a specific role under **Settings → Roles → Assignment tab** to limit what they can access.
Create an API key in **Settings → API & Webhooks → + Create key**. Copy it immediately — it's shown once. Keys can be scoped to a specific role under **Settings → Members → Roles → Assignment tab** to limit what they can access.
<VimeoEmbed videoId="928786722" title="Creating API key" />
@@ -83,7 +83,7 @@ Your API key grants access to sensitive data. Don't share it with untrusted serv
For better security, assign a specific role to limit access:
1. Go to **Settings → Roles**
1. Go to **Settings → Members → Roles**
2. Click on the role to assign
3. Open the **Assignment** tab
4. Under **API Keys**, click **+ Assign to API key**
@@ -37,7 +37,7 @@ Beide sind als REST und GraphQL verfügbar. GraphQL bietet Batch-Upserts und die
Authorization: Bearer YOUR_API_KEY
```
Erstellen Sie einen API-Schlüssel unter **Settings > APIs & Webhooks > + Create key**. Kopieren Sie ihn sofort — er wird nur einmal angezeigt. Schlüssel können unter **Settings > Roles > Assignment tab** auf eine bestimmte Rolle beschränkt werden, um ihren Zugriff einzuschränken.
Erstellen Sie einen API-Schlüssel unter **Settings > APIs & Webhooks > + Create key**. Kopieren Sie ihn sofort — er wird nur einmal angezeigt. Schlüssel können unter **Settings → Members → Roles Assignment tab** auf eine bestimmte Rolle beschränkt werden, um ihren Zugriff einzuschränken.
<VimeoEmbed videoId="928786722" title="API-Schlüssel erstellen" />
@@ -88,7 +88,7 @@ Ihr API-Schlüssel gewährt Zugriff auf sensible Daten. Teilen Sie ihn nicht mit
Für mehr Sicherheit weisen Sie eine spezifische Rolle zu, um den Zugriff zu beschränken:
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
3. Öffnen Sie den Tab **Zuweisungen**
4. Unter **API-Schlüssel** auf **+ API-Schlüssel zuweisen** klicken
@@ -9,7 +9,7 @@ KI-Agenten respektieren Ihre bestehende Berechtigungsstruktur. Dies ist besonder
## Weisen Sie einem KI-Agenten eine Rolle zu
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
3. Öffnen Sie den Tab **Zuweisungen**
4. Unter **KI-Agenten** klicken Sie auf **+ KI-Agent zuweisen**
@@ -17,7 +17,7 @@ description: Häufig gestellte Fragen zu KI-Funktionen in Twenty.
</Accordion>
<Accordion title="Haben KI-Agenten Zugriff auf alle meine Daten?">
KI-Agenten werden über das Berechtigungssystem verwaltet. Sie können KI-Agenten unter **Einstellungen → Rollen** bestimmte Rollen zuweisen und haben damit volle Kontrolle darüber, auf welche Daten sie zugreifen können und welche Aktionen sie ausführen dürfen.
KI-Agenten werden über das Berechtigungssystem verwaltet. Sie können KI-Agenten unter **Einstellungen → Mitglieder → Rollen** bestimmte Rollen zuweisen und haben damit volle Kontrolle darüber, auf welche Daten sie zugreifen können und welche Aktionen sie ausführen dürfen.
</Accordion>
<Accordion title="Wie funktionieren KI-Credits?">
@@ -48,7 +48,7 @@ Erweitern Sie Ihre Workflows mit KI-gestützten Aktionen und autonomen Agenten.
KI-Agenten werden über das bestehende Berechtigungssystem verwaltet:
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Konfigurieren Sie, auf welche Daten jeder KI-Agent zugreifen kann
3. Legen Sie Lese-/Schreibberechtigungen pro Objekt fest
@@ -214,7 +214,7 @@ Schließen Sie nach dem Import der Daten die Konfiguration Ihres Arbeitsbereichs
### Rollen und Berechtigungen konfigurieren
* Richten Sie Rollen unter **Einstellungen → Rollen** ein
* Richten Sie Rollen unter **Einstellungen → Mitglieder → Rollen** ein
* Weisen Sie Benutzer den entsprechenden Rollen zu
### E-Mail und Kalender verbinden
@@ -127,7 +127,7 @@ Erstellen Sie nach dem Import der Daten manuell neu:
### Rollen und Berechtigungen
* Konfigurieren Sie Rollen in **Einstellungen → Rollen**
* Richten Sie Rollen unter **Einstellungen → Mitglieder → Rollen** ein
* Weisen Sie Benutzer den entsprechenden Rollen zu
### Integrationen
@@ -13,7 +13,7 @@ Das Berechtigungssystem von Twenty ermöglicht es Ihnen, den Zugriff auf drei Ha
Um eine neue Rolle zu erstellen:
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Unter **Alle Rollen** klicken Sie auf **+ Rolle erstellen**
3. Geben Sie einen Rollennamen ein
4. Im Standard-Tab **Berechtigungen** [Berechtigungen konfigurieren](#customize-permissions)
@@ -23,7 +23,7 @@ Um eine neue Rolle zu erstellen:
Um eine Rolle zu löschen:
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Klicken Sie auf die Rolle, die Sie entfernen möchten
3. Öffnen Sie den Tab **Einstellungen** und klicken Sie auf **Rolle löschen**
4. Klicken Sie im Modal auf **Bestätigen**
@@ -36,13 +36,13 @@ Wenn eine Rolle gelöscht wird, wird jedes ihr zugewiesene Mitglied des Arbeitsb
### Aktuelle Zuweisungen anzeigen
* Gehen Sie zu **Einstellungen → Rollen**
* Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
* Sehen Sie alle Rollen und wie viele Mitglieder jeweils zugewiesen sind
* Anzeigen, welche Mitglieder welche Rollen haben
### Weisen Sie einem Mitglied eine Rolle zu
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
3. Öffnen Sie den Tab **Zuweisungen**
4. Klicken Sie auf **+ Mitglied zuweisen**
@@ -51,7 +51,7 @@ Wenn eine Rolle gelöscht wird, wird jedes ihr zugewiesene Mitglied des Arbeitsb
### Standardrolle festlegen
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Suchen Sie im Abschnitt **Optionen** nach **Standardrolle**
3. Wählen Sie aus, welche Rolle neue Mitglieder automatisch erhalten sollen
4. Neue Arbeitsbereichsmitglieder werden beim Beitritt dieser Rolle zugewiesen
@@ -168,7 +168,7 @@ Neben Mitgliedern des Arbeitsbereichs können Rollen auch **API-Schlüsseln** un
### Einem API-Schlüssel eine Rolle zuweisen
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
3. Öffnen Sie den Tab **Zuweisungen**
4. Unter **API-Schlüssel** auf **+ API-Schlüssel zuweisen** klicken
@@ -183,7 +183,7 @@ API-Schlüssel ohne zugewiesene Rolle verwenden Standardberechtigungen. Weisen S
### Einem KI-Agenten eine Rolle zuweisen
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Klicken Sie auf die Rolle, die Sie zuweisen möchten
3. Öffnen Sie den Tab **Zuweisungen**
4. Unter **KI-Agenten** auf **+ KI-Agenten zuweisen** klicken
@@ -19,7 +19,7 @@ Jedes Mitglied des Arbeitsbereichs, dem diese Rolle zugewiesen ist, wird automat
</Accordion>
<Accordion title="Wie lege ich eine Standardrolle für neue Mitglieder fest?">
Gehen Sie zu **Einstellungen → Rollen**, suchen Sie die Option **Standardrolle** und wählen Sie aus, welche Rolle neue Mitglieder beim Beitritt automatisch erhalten sollen.
Gehen Sie zu **Einstellungen → Mitglieder → Rollen**, suchen Sie die Option **Standardrolle** und wählen Sie aus, welche Rolle neue Mitglieder beim Beitritt automatisch erhalten sollen.
</Accordion>
<Accordion title="Kann ich einem Benutzer mehrere Rollen zuweisen?">
@@ -64,7 +64,7 @@ Berechtigungen auf Zeilenebene werden bis Q1 2026 im Tarif **Organization** verf
</Accordion>
<Accordion title="Wie mache ich ein Feld für bestimmte Benutzer schreibgeschützt?">
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Wählen Sie die Rolle aus
3. Navigieren Sie zu dem Objekt, das das Feld enthält
4. Setzen Sie die Feldberechtigung auf **Feld anzeigen** (ohne Feld bearbeiten)
@@ -3,10 +3,12 @@ title: Domäneneinstellungen
description: Konfigurieren Sie die Arbeitsbereichsdomäne, genehmigte Zugriffsdomänen und öffentliche Domänen.
---
Konfigurieren Sie die Domäneneinstellungen unter **Einstellungen → Domänen**.
Domain-Einstellungen befinden sich an drei Stellen, abhängig davon, was Sie konfigurieren.
## Arbeitsbereichsdomäne
Konfigurieren Sie dies unter **Einstellungen → Allgemein → Arbeitsbereichs-Domain**.
Bearbeiten Sie den Namen Ihrer Subdomäne oder legen Sie eine benutzerdefinierte Domäne für Ihren Arbeitsbereich fest.
### Domäne anpassen
@@ -19,6 +21,8 @@ Für benutzerdefinierte Domänen müssen Sie die DNS-Einstellungen bei Ihrem Dom
## Genehmigte Domänen
Konfigurieren Sie dies unter **Einstellungen → Mitglieder → Einladen**.
Jede Person mit einer E-Mail-Adresse in diesen Domänen darf sich automatisch für diesen Arbeitsbereich registrieren.
### Genehmigte Zugriffsdomäne hinzufügen
@@ -35,13 +39,16 @@ Dies ist nützlich, um Ihrem gesamten Team die Selbstregistrierung zu ermöglich
## Öffentliche Domains
Stellen Sie eine vollständige und sichere Hosting-Umgebung auf diesen Domains bereit.
Konfigurieren Sie dies unter **Einstellungen → Apps → Entwickler**.
Stellen Sie eine vollständige und sichere Hosting-Umgebung auf diesen Domains bereit. Eine öffentliche Domain kann an eine bestimmte App gebunden werden wenn sie gebunden ist, sind unter dieser Domain nur die HTTP-gerouteten Logikfunktionen dieser App erreichbar. Lassen Sie die Bindung leer, um alle HTTP-Routen des Arbeitsbereichs bereitzustellen.
### Öffentliche Domäne hinzufügen
1. Klicken Sie auf **Öffentliche Domäne hinzufügen**
2. Geben Sie die Domäne ein, die Sie verwenden möchten
3. Konfigurieren Sie die DNS-Einstellungen gemäß Anleitung
4. Überprüfen Sie die Domäne
3. Optional an eine App binden
4. Konfigurieren Sie die DNS-Einstellungen gemäß Anleitung
5. Überprüfen Sie die Domäne
SSL-Zertifikate werden für öffentliche Domänen automatisch bereitgestellt.
@@ -77,7 +77,7 @@ Verwalten Sie Einladungen, die noch nicht angenommen wurden:
Erlauben Sie Teammitgliedern, basierend auf ihrer E-Mail-Domäne automatisch beizutreten:
1. Gehen Sie zu **Einstellungen → Domänen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Einladen**
2. Fügen Sie die Domäne Ihres Unternehmens hinzu (z. B. `yourcompany.com`)
3. Jede Person mit dieser E-Mail-Domäne kann ohne Einladung beitreten
@@ -137,7 +137,7 @@ Ja, Sie können mehrere E-Mail-Konten verbinden. Gehen Sie zu **Einstellungen
<AccordionGroup>
<Accordion title="Kann ich meine Arbeitsbereichsdomäne anpassen?">
Ja! Gehen Sie zu **Einstellungen → Domänen** und klicken Sie auf **Domäne anpassen**. Sie haben zwei Optionen:
Ja! Gehen Sie zu **Einstellungen → Allgemein → Workspace-Domäne** und klicken Sie auf **Domäne anpassen**. Sie haben zwei Optionen:
* **Subdomain**: Verwenden Sie eine Twenty-Subdomain wie `yourcompany.twenty.com`
* **Benutzerdefinierte Domäne**: Verwenden Sie Ihre eigene Domäne wie `crm.yourcompany.com` (erfordert DNS-Konfiguration)
@@ -146,7 +146,7 @@ Eine Subdomain ist schnell eingerichtet, während eine benutzerdefinierte Domän
</Accordion>
<Accordion title="Wie funktionieren genehmigte Zugriffsdomänen?">
Sie können genehmigte Zugriffsdomänen konfigurieren, damit Teammitglieder mit Firmen-E-Mail-Adressen Ihrem Arbeitsbereich automatisch beitreten können. Gehen Sie zu **Einstellungen → Domänen** und fügen Sie Ihre Firmendomäne hinzu (z. B. `yourcompany.com`).
Sie können genehmigte Zugriffsdomänen konfigurieren, damit Teammitglieder mit Firmen-E-Mail-Adressen Ihrem Arbeitsbereich automatisch beitreten können. Gehen Sie zu **Einstellungen → Mitglieder → Einladen** und fügen Sie Ihre Firmendomäne hinzu (z. B. `yourcompany.com`).
</Accordion>
</AccordionGroup>
@@ -44,7 +44,7 @@ Fügen Sie Ihrem Arbeitsbereich Teammitglieder hinzu:
4. Weisen Sie geeignete Rollen zu
<Note>
Bevor Sie Ihr Team einladen, überprüfen Sie die Standardrolle unter **Einstellungen → Rollen**. Neuen Mitgliedern wird diese Rolle beim Beitritt automatisch zugewiesen.
Bevor Sie Ihr Team einladen, überprüfen Sie die Standardrolle unter **Einstellungen → Mitglieder → Rollen**. Neuen Mitgliedern wird diese Rolle beim Beitritt automatisch zugewiesen.
</Note>
## Checkliste für Arbeitsbereichseinstellungen
@@ -38,7 +38,7 @@ Sie benötigen zwei benutzerdefinierte Felder am Objekt „Opportunities“.
Wenn Benutzer diese berechneten Felder nicht manuell bearbeiten sollen:
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Wählen Sie die zu konfigurierende Rolle aus
3. Suchen Sie das Objekt „Opportunities“
4. Setzen Sie die Felder **Probability** und **Expected Amount** auf schreibgeschützt
@@ -61,7 +61,7 @@ Sie benötigen keine "Days in"-Felder für Closed Won und Closed Lost, da dies f
Wenn Benutzer diese berechneten Felder nicht manuell bearbeiten sollen:
1. Gehen Sie zu **Einstellungen → Rollen**
1. Gehen Sie zu **Einstellungen → Mitglieder → Rollen**
2. Rolle zum Konfigurieren auswählen
3. Suchen Sie das Objekt Opportunities
4. Setzen Sie die Felder "Last Entered" und "Days in" auf schreibgeschützt
@@ -307,5 +307,5 @@ AI Agent actions consume workflow credits based on the AI model used. See [Workf
</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/de/user-guide/permissions-access/capabilities/permissions) for details.
AI agents respect role-based permissions. Sie können Agenten unter **Einstellungen → Mitglieder → Rollen** bestimmte Rollen zuweisen, um zu steuern, auf welche Daten sie zugreifen können. See [Permissions](/l/de/user-guide/permissions-access/capabilities/permissions) for details.
</Note>
@@ -8,7 +8,7 @@ description: Häufig gestellte Fragen zu Workflows in Twenty.
<Accordion title="Warum kann ich einen Workflow nicht aktivieren?">
Dies ist wahrscheinlich ein Berechtigungsproblem. Sie benötigen Zugriff auf Workflows, um sie zu erstellen und zu aktivieren.
**Lösung**: Wenden Sie sich an Ihren Workspace-Administrator, damit er Ihnen unter **Einstellungen → Rollen** Zugriff auf Workflows gewährt.
**Lösung**: Wenden Sie sich an Ihren Workspace-Administrator, damit er Ihnen unter **Einstellungen → Mitglieder → Rollen** Zugriff auf Workflows gewährt.
Wenn Sie den Bereich Workflows in Ihrer Seitenleiste überhaupt nicht sehen, bestätigt dies ein Berechtigungsproblem.
</Accordion>
@@ -37,7 +37,7 @@ Ambas estão disponíveis como REST e GraphQL. GraphQL adiciona upserts em lote
Authorization: Bearer YOUR_API_KEY
```
Crie uma chave de API em **Settings → API & Webhooks → + Create key**. Copie-a imediatamente — ela é exibida apenas uma vez. As chaves podem ter escopo para uma função específica em **Settings → Roles → Assignment tab** para limitar o que podem acessar.
Crie uma chave de API em **Settings → API & Webhooks → + Create key**. Copie-a imediatamente — ela é exibida apenas uma vez. As chaves podem ser limitadas a uma função específica em **Settings → Members → Roles → Assignment tab** para restringir o que podem acessar.
<VimeoEmbed videoId="928786722" title="Criando chave de API" />
@@ -88,7 +88,7 @@ Sua chave de API concede acesso a dados confidenciais. Não a compartilhe com se
Para maior segurança, atribua uma função específica para limitar o acesso:
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Clique na função que deseja atribuir
3. Abra a aba de **Atribuição**
4. Em **Chaves de API**, clique em **+ Atribuir à chave de API**
@@ -9,7 +9,7 @@ Os agentes de IA respeitam sua estrutura de permissões existente. Isso é parti
## Atribuir uma Função a um Agente de IA
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Clique na função que deseja atribuir
3. Abra a aba de **Atribuição**
4. Em **Agentes de IA**, clique em **+ Atribuir ao agente de IA**
@@ -17,7 +17,7 @@ description: Perguntas frequentes sobre recursos de IA na Twenty.
</Accordion>
<Accordion title="Os agentes de IA terão acesso a todos os meus dados?">
Os agentes de IA funcionarão de acordo com o sistema de permissões. Você pode atribuir funções específicas aos agentes de IA em **Configurações → Funções**, dando a você controle total sobre quais dados eles podem acessar e quais ações podem executar.
Os agentes de IA funcionarão de acordo com o sistema de permissões. Você pode atribuir funções específicas aos agentes de IA em **Configurações → Membros → Funções**, dando a você controle total sobre quais dados eles podem acessar e quais ações podem executar.
</Accordion>
<Accordion title="Como os créditos de IA vão funcionar?">
@@ -48,7 +48,7 @@ Amplie seus fluxos de trabalho com ações com IA e agentes autônomos.
Os agentes de IA serão gerenciados pelo sistema de permissões existente:
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Configure quais dados cada agente de IA pode acessar
3. Defina permissões de leitura/gravação por objeto
@@ -214,7 +214,7 @@ Após importar os dados, complete a configuração do seu espaço de trabalho:
### Configure funções e permissões
* Configure as funções em **Definições → Funções**
* Configure as funções em **Definições → Membros → Funções**
* Atribua os utilizadores às funções apropriadas
### Ligue o e-mail e o calendário
@@ -127,7 +127,7 @@ Depois de importar os dados, recrie manualmente:
### Funções e Permissões
* Configure as funções em **Configurações → Funções**
* Configure as funções em **Definições → Membros → Funções**
* Atribua os utilizadores às funções apropriadas
### Integrações
@@ -13,7 +13,7 @@ O sistema de permissões do Twenty permite que você controle o acesso a três
Para criar uma nova função:
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Em **Todas as Funções**, clique em **+ Criar Função**
3. Digite um nome para a função
4. Na aba padrão **Permissões**, [configure as permissões](#customize-permissions)
@@ -23,7 +23,7 @@ Para criar uma nova função:
Para excluir uma função:
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Clique na função que deseja remover
3. Abra a aba de **Configurações** e clique em **Excluir Função**
4. Clique em **Confirmar** no modal
@@ -36,13 +36,13 @@ Se uma função for excluída, qualquer membro do espaço de trabalho atribuído
### Visualizar Atribuições Atuais
* Vá para **Configurações → Funções**
* Vá para **Configurações → Membros → Funções**
* Veja todas as funções e quantos membros estão atribuídos a cada uma
* Veja quais membros têm quais funções
### Atribuir uma Função a um Membro
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Clique na função que deseja atribuir
3. Abra a aba de **Atribuição**
4. Clique em **+ Atribuir a membro**
@@ -51,7 +51,7 @@ Se uma função for excluída, qualquer membro do espaço de trabalho atribuído
### Definir Função Padrão
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Na seção **Opções**, encontre **Função Padrão**
3. Selecione qual função novos membros devem receber automaticamente
4. Novos membros do espaço de trabalho serão atribuídos a essa função ao ingressar
@@ -168,7 +168,7 @@ Além dos membros do espaço de trabalho, funções também podem ser atribuída
### Atribuir uma função a uma chave de API
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Clique na função que deseja atribuir
3. Abra a aba de **Atribuição**
4. Em **Chaves de API**, clique em **+ Atribuir à chave de API**
@@ -183,7 +183,7 @@ Chaves de API sem uma função atribuída usam permissões padrão. Para maior s
### Atribuir uma função a um agente de IA
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Clique na função que deseja atribuir
3. Abra a aba de **Atribuição**
4. Em **Agentes de IA**, clique em **+ Atribuir ao agente de IA**
@@ -19,7 +19,7 @@ Qualquer membro do espaço de trabalho atribuído a essa função será automati
</Accordion>
<Accordion title="Como defino uma função padrão para novos membros?">
Vá para **Configurações → Funções**, encontre a opção **Função Padrão** e selecione qual função os novos membros devem receber automaticamente ao entrar.
Vá para **Configurações → Membros → Funções**, encontre a opção **Função Padrão** e selecione qual função os novos membros devem receber automaticamente ao entrar.
</Accordion>
<Accordion title="Posso atribuir várias funções a um único usuário?">
@@ -64,7 +64,7 @@ As permissões em nível de linha estarão disponíveis no plano **Organization*
</Accordion>
<Accordion title="Como deixar um campo somente leitura para determinados usuários?">
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Selecione a função
3. Navegue até o objeto que contém o campo
4. Defina a permissão do campo como **Ver campo** (sem Editar campo)
@@ -3,10 +3,12 @@ title: Configurações de Domínio
description: Configure o domínio do espaço de trabalho, os domínios de acesso aprovados e os domínios públicos.
---
Configure as configurações de domínio em **Configurações → Domínios**.
As configurações de domínio ficam em três lugares, dependendo do que você está configurando.
## Domínio do espaço de trabalho
Configure em **Configurações → Geral → Domínio do workspace**.
Edite o nome do seu subdomínio ou defina um domínio personalizado para o seu espaço de trabalho.
### Personalizar domínio
@@ -19,6 +21,8 @@ Para domínios personalizados, você precisará configurar as configurações de
## Domínios Aprovados
Configure em **Configurações → Membros → Convite**.
Qualquer pessoa com um endereço de e-mail nesses domínios pode inscrever-se neste espaço de trabalho automaticamente.
### Adicionar Domínio de Acesso Aprovado
@@ -35,13 +39,16 @@ Isso é útil para permitir que toda a sua equipe se registre por conta própria
## Domínios Públicos
Provisionar um ambiente de hospedagem completo e seguro nestes domínios.
Configure em **Configurações → Aplicativos → Desenvolvedor**.
Provisionar um ambiente de hospedagem completo e seguro nestes domínios. Um domínio público pode ser vinculado a um app específico — quando vinculado, somente as funções de lógica roteadas por HTTP desse app ficam acessíveis no domínio. Deixe a vinculação vazia para expor todas as rotas HTTP do workspace.
### Adicionar Domínio Público
1. Clique em **Adicionar Domínio Público**
2. Insira o domínio que você deseja usar
3. Configure as configurações de DNS conforme as instruções
4. Verifique o domínio
3. Opcionalmente vincule-o a um app
4. Configure as configurações de DNS conforme as instruções
5. Verifique o domínio
Os certificados SSL são provisionados automaticamente para domínios públicos.
@@ -77,7 +77,7 @@ Gerencie convites que ainda não foram aceitos:
Permita que membros da equipe ingressem automaticamente com base no domínio de e-mail:
1. Vá para **Configurações → Domínios**
1. Vá para **Configurações → Membros → Convites**
2. Adicione o domínio da sua empresa (por exemplo, `yourcompany.com`)
3. Qualquer pessoa com esse domínio de e-mail pode ingressar sem convite
@@ -137,7 +137,7 @@ Sim, você pode conectar várias contas de e-mail. Vá para **Configurações
<AccordionGroup>
<Accordion title="Posso personalizar o domínio do meu espaço de trabalho?">
Sim! Vá para **Configurações → Domínios** e clique em **Personalizar domínio**. Você tem duas opções:
Sim! Vá para **Configurações → Geral → Domínio do espaço de trabalho** e clique em **Personalizar domínio**. Você tem duas opções:
* **Subdomínio**: Use um subdomínio do Twenty como `yourcompany.twenty.com`
* **Domínio personalizado**: Use seu próprio domínio, como `crm.yourcompany.com` (requer configuração de DNS)
@@ -146,7 +146,7 @@ Um subdomínio é rápido de configurar, enquanto um domínio personalizado ofer
</Accordion>
<Accordion title="Como funcionam os domínios de acesso aprovados?">
Você pode configurar domínios de acesso aprovados para que membros da equipe com endereços de e-mail da empresa possam ingressar automaticamente no seu espaço de trabalho. Vá para **Configurações → Domínios** e adicione o domínio da sua empresa (por exemplo, `yourcompany.com`).
Você pode configurar domínios de acesso aprovados para que membros da equipe com endereços de e-mail da empresa possam ingressar automaticamente no seu espaço de trabalho. Vá para **Configurações → Membros → Convidar** e adicione o domínio da sua empresa (por exemplo, `yourcompany.com`).
</Accordion>
</AccordionGroup>
@@ -44,7 +44,7 @@ Adicione membros da equipa ao seu espaço de trabalho:
4. Atribua funções apropriadas
<Note>
Antes de convidar a sua equipa, verifique a função padrão em **Configurações → Funções**. Novos membros recebem automaticamente essa função ao entrar.
Antes de convidar a sua equipa, verifique a função padrão em **Configurações → Membros → Funções**. Novos membros recebem automaticamente essa função ao entrar.
</Note>
## Lista de Verificação das Configurações do Espaço de Trabalho
@@ -38,7 +38,7 @@ Você precisa de dois campos personalizados no objeto Oportunidades.
Se você não quiser que os usuários editem manualmente esses campos calculados:
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Selecione a função a configurar
3. Encontre o objeto Oportunidades
4. Defina os campos **Probability** e **Expected Amount** como somente leitura
@@ -61,7 +61,7 @@ Você não precisa de campos "Dias em" para Fechado Ganho e Fechado Perdido, poi
Se você não quiser que os usuários editem manualmente esses campos calculados:
1. Vá para **Configurações → Funções**
1. Vá para **Configurações → Membros → Funções**
2. Selecione a função a configurar
3. Encontre o objeto Oportunidades
4. Defina os campos "Última entrada" e "Dias em" como somente leitura
@@ -307,5 +307,5 @@ As ações do Agente de IA consomem créditos de fluxo de trabalho com base no m
</Note>
<Note>
Os agentes de IA respeitam permissões baseadas em funções. Você pode atribuir funções específicas aos agentes em **Configurações → Funções** para controlar a quais dados eles podem acessar. Veja [Permissões](/l/pt/user-guide/permissions-access/capabilities/permissions) para obter detalhes.
Os agentes de IA respeitam permissões baseadas em funções. Você pode atribuir funções específicas aos agentes em **Configurações → Membros → Funções** para controlar a quais dados eles podem acessar. Veja [Permissões](/l/pt/user-guide/permissions-access/capabilities/permissions) para obter detalhes.
</Note>
@@ -8,7 +8,7 @@ description: Perguntas frequentes sobre fluxos de trabalho na Twenty.
<Accordion title="Por que não consigo ativar um fluxo de trabalho?">
Isso provavelmente é um problema de permissões. Você precisa de acesso a fluxos de trabalho para criá-los e ativá-los.
**Solução**: Entre em contato com o administrador do seu espaço de trabalho para conceder acesso a fluxos de trabalho em **Configurações → Funções**.
**Solução**: Entre em contato com o administrador do seu espaço de trabalho para conceder acesso a fluxos de trabalho em **Configurações → Membros → Funções**.
Se você não vê a seção de fluxos de trabalho na sua barra lateral, isso confirma que é um problema de permissões.
</Accordion>
@@ -37,7 +37,7 @@ Ambele sunt disponibile ca REST și GraphQL. GraphQL adaugă upsert-uri în lot
Authorization: Bearer YOUR_API_KEY
```
Creează o cheie API în **Settings → API & Webhooks → + Create key**. Copiază-o imediat — este afișată o singură dată. Cheile pot fi limitate la un rol specific în **Settings → Roles → Assignment tab** pentru a restricționa la ce pot avea acces.
Creează o cheie API în **Settings → API & Webhooks → + Create key**. Copiază-o imediat — este afișată o singură dată. Cheile pot fi limitate la un rol specific în **Settings → Members → Roles → Assignment tab** pentru a restricționa la ce pot avea acces.
<VimeoEmbed videoId="928786722" title="Crearea unei chei API" />
@@ -88,7 +88,7 @@ Cheia dvs. API oferă acces la date sensibile. Nu o partajați cu servicii care
Pentru o securitate sporită, atribuiți un rol specific pentru a limita accesul:
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Faceți clic pe rolul pe care doriți să-l atribuiți
3. Deschideți fila **Atribuire**
4. În **API Keys**, faceți clic pe **+ Assign to API key**
@@ -9,7 +9,7 @@ Agenții AI respectă structura de permisiuni existentă. Acest lucru este deose
## Atribuiți un Rol unui Agent AI
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Faceți clic pe rolul pe care doriți să-l atribuiți
3. Deschideți fila **Atribuire**
4. În **Agenți AI**, faceți clic pe **+ Atribuiți agentului AI**
@@ -17,7 +17,7 @@ description: Întrebări frecvente despre funcționalitățile IA din Twenty.
</Accordion>
<Accordion title="Vor avea agenții IA acces la toate datele mele?">
Agenții IA vor funcționa conform sistemului de permisiuni. Puteți atribui agenților IA roluri specifice în **Settings → Roles**, oferindu-vă control total asupra datelor la care pot avea acces și a acțiunilor pe care le pot efectua.
Agenții IA vor funcționa conform sistemului de permisiuni. Puteți atribui agenților IA roluri specifice în **Settings → Members → Roles**, oferindu-vă control total asupra datelor la care pot avea acces și a acțiunilor pe care le pot efectua.
</Accordion>
<Accordion title="Cum vor funcționa creditele IA?">
@@ -48,7 +48,7 @@ Extinde-ți fluxurile de lucru cu acțiuni bazate pe IA și agenți autonomi.
Agenții IA vor fi gestionați prin sistemul de permisiuni existent:
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Configurează la ce date poate avea acces fiecare agent IA
3. Stabilește permisiuni de citire/scriere pentru fiecare obiect
@@ -214,7 +214,7 @@ După importul datelor, finalizați configurarea spațiului de lucru:
### Configurați roluri și permisiuni
* Configurați rolurile în **Setări → Roluri**
* Configurați rolurile în **Setări → Membri → Roluri**
* Atribuiți utilizatorilor rolurile corespunzătoare
### Conectați e-mailul și calendarul
@@ -127,7 +127,7 @@ După importarea datelor, recreați manual:
### Roluri și permisiuni
* Configurați rolurile în **Setări → Roluri**
* Configurați rolurile în **Setări → Membri → Roluri**
* Atribuiți utilizatorilor rolurile corespunzătoare
### Integrări
@@ -13,7 +13,7 @@ Sistemul de permisiuni al Twenty vă permite să controlați accesul la trei dom
Pentru a crea un rol nou:
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Sub **Toate Rolurile**, faceți clic pe **+ Creează Rol**
3. Introduceți un nume de rol
4. În fila implicită **Permisiuni**, [configurați permisiunile](#customize-permissions)
@@ -23,7 +23,7 @@ Pentru a crea un rol nou:
Pentru a șterge un rol:
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Faceți clic pe rolul pe care doriți să-l eliminați
3. Deschideți tab-ul **Setări**, apoi faceți clic pe **Șterge Rol**
4. Faceți clic pe **Confirmă** în fereastra modală
@@ -36,13 +36,13 @@ Dacă un rol este șters, orice membru al workspace-ului alocat acestuia va fi r
### Vizualizați Atribuirile Curente
* Accesați **Setări → Roluri**
* Accesați **Setări → Membri → Roluri**
* Vedeți toate rolurile și câți membri sunt alocați fiecăruia
* Vizualizați ce membri au ce roluri
### Atribuiți un Rol unui Membru
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Faceți clic pe rolul pe care doriți să-l atribuiți
3. Deschideți fila **Atribuire**
4. Faceți clic pe **+ Atribuie membrului**
@@ -51,7 +51,7 @@ Dacă un rol este șters, orice membru al workspace-ului alocat acestuia va fi r
### Setați Rolul Implicit
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. În secțiunea **Opțiuni**, găsiți **Rol Implicit**
3. Selectați ce rol ar trebui să primească automat noii membri
4. Noii membri ai workspace-ului vor primi acest rol când se alătură
@@ -168,7 +168,7 @@ Pe lângă membrii workspace-ului, rolurile pot fi atribuite și cheilor API și
### Atribuiți un rol unei chei API
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Faceți clic pe rolul pe care doriți să-l atribuiți
3. Deschideți fila **Atribuire**
4. În **API Keys**, faceți clic pe **+ Assign to API key**
@@ -183,7 +183,7 @@ Cheile API fără un rol atribuit folosesc permisiunile implicite. Pentru o secu
### Atribuiți un rol unui agent AI
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Faceți clic pe rolul pe care doriți să-l atribuiți
3. Deschideți fila **Atribuire**
4. În **AI Agents**, faceți clic pe **+ Assign to AI agent**
@@ -19,7 +19,7 @@ Orice membru al spațiului de lucru atribuit acelui rol va fi reatribuit automat
</Accordion>
<Accordion title="Cum setez un rol implicit pentru noii membri?">
Accesați **Settings → Roles**, găsiți opțiunea **Default Role** și selectați ce rol ar trebui să primească automat noii membri când se alătură.
Accesați **Setări → Membri → Roluri**, găsiți opțiunea **Default Role** și selectați ce rol ar trebui să primească automat noii membri când se alătură.
</Accordion>
<Accordion title="Pot să atribui mai multe roluri unui singur utilizator?">
@@ -64,7 +64,7 @@ Permisiunile la nivel de rând vor fi disponibile în planul **Organization** p
</Accordion>
<Accordion title="Cum fac un câmp doar pentru citire pentru anumiți utilizatori?">
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Selectați rolul
3. Navigați la obiectul care conține câmpul
4. Setați permisiunea câmpului la **See Field** (fără Edit Field)
@@ -3,10 +3,12 @@ title: Setări domeniu
description: Configurați domeniul spațiului de lucru, domeniile de acces aprobate și domeniile publice.
---
Configurați setările de domeniu în **Setări → Domenii**.
Setările de domeniu se află în trei locuri, în funcție de ceea ce configurați.
## Domeniu Spațiu de lucru
Configurați în **Setări → General → Domeniu al spațiului de lucru**.
Editați numele subdomeniului sau setați un domeniu personalizat pentru spațiul de lucru.
### Personalizează Domeniul
@@ -19,6 +21,8 @@ Pentru domeniile personalizate, va trebui să configurați setările DNS la furn
## Domenii Aprobate
Configurați în **Setări → Membri → Invită**.
Oricine are o adresă de email pe aceste domenii se poate înscrie automat în acest spațiu de lucru.
### Adaugă Domeniu de Acces Aprobat
@@ -35,13 +39,16 @@ Acest lucru este util pentru a permite întregii echipe să se înregistreze sin
## Domenii Publice
Provisionați un mediu de găzduire complet și sigur pe aceste domenii.
Configurați în **Setări → Aplicații → Dezvoltator**.
Provisionați un mediu de găzduire complet și sigur pe aceste domenii. Un domeniu public poate fi asociat cu o anumită aplicație — când este asociat, numai funcțiile de logică rutată HTTP ale acelei aplicații sunt accesibile pe domeniu. Lăsați asocierea goală pentru a expune toate rutele HTTP ale spațiului de lucru.
### Adaugă Domeniu Public
1. Faceți clic pe **Adăugați domeniu public**
2. Introduceți domeniul pe care doriți să îl utilizați
3. Configurați setările DNS conform instrucțiunilor
4. Verificați domeniul
3. Opțional, asociați-l unei aplicații
4. Configurați setările DNS conform instrucțiunilor
5. Verificați domeniul
Certificatele SSL sunt furnizate automat pentru domeniile publice.
@@ -77,7 +77,7 @@ Gestionați invitațiile care nu au fost acceptate:
Permiteți membrilor echipei să se alăture automat pe baza domeniului lor de e-mail:
1. Accesați **Setări → Domenii**
1. Accesați **Setări → Membri → Invită**
2. Adăugați domeniul companiei dvs. (de ex., `yourcompany.com`)
3. Oricine are acel domeniu de e-mail se poate alătura fără invitație
@@ -137,7 +137,7 @@ Da, puteți conecta mai multe conturi de e-mail. Accesați **Setări → Conturi
<AccordionGroup>
<Accordion title="Pot personaliza domeniul spațiului meu de lucru?">
Da! Accesați **Setări → Domenii** și faceți clic pe **Personalizează domeniul**. Aveți două opțiuni:
Da! Accesați **Setări → General → Domeniul spațiului de lucru** și faceți clic pe **Personalizează domeniul**. Aveți două opțiuni:
* **Subdomeniu**: Folosiți un subdomeniu Twenty, de exemplu `yourcompany.twenty.com`
* **Domeniu personalizat**: Folosiți propriul domeniu, de exemplu `crm.yourcompany.com` (necesită configurarea DNS)
@@ -146,7 +146,7 @@ Un subdomeniu se configurează rapid, în timp ce un domeniu personalizat oferă
</Accordion>
<Accordion title="Cum funcționează domeniile de acces aprobate?">
Puteți configura domenii de acces aprobate astfel încât membrii echipei cu adrese de e-mail ale companiei să se poată alătura automat spațiului dvs. de lucru. Accesați **Setări → Domenii** și adăugați domeniul companiei (de ex., `yourcompany.com`).
Puteți configura domenii de acces aprobate astfel încât membrii echipei cu adrese de e-mail ale companiei să se poată alătura automat spațiului dvs. de lucru. Accesați **Setări → Membri → Invită** și adăugați domeniul companiei (de ex., `yourcompany.com`).
</Accordion>
</AccordionGroup>
@@ -44,7 +44,7 @@ Adăugați membri ai echipei în spațiul de lucru:
4. Atribuiți rolurile corespunzătoare
<Note>
Înainte de a vă invita echipa, verificați rolul implicit în **Setări → Roluri**. Noilor membri li se atribuie automat acest rol când se alătură.
Înainte de a vă invita echipa, verificați rolul implicit în **Setări → Membri → Roluri**. Noilor membri li se atribuie automat acest rol când se alătură.
</Note>
## Listă de verificare pentru setările spațiului de lucru
@@ -38,7 +38,7 @@ Aveți nevoie de două câmpuri personalizate pe obiectul Oportunități.
Dacă nu doriți ca utilizatorii să editeze manual aceste câmpuri calculate:
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Selectați rolul pe care doriți să-l configurați
3. Găsiți obiectul Oportunități
4. Setați câmpurile **Probabilitate** și **Sumă estimată** ca numai în citire
@@ -61,7 +61,7 @@ Nu aveți nevoie de câmpuri "Zile în" pentru Închis - câștigat și Închis
Dacă nu doriți ca utilizatorii să editeze manual aceste câmpuri calculate:
1. Accesați **Setări → Roluri**
1. Accesați **Setări → Membri → Roluri**
2. Selectați rolul de configurat
3. Găsiți obiectul Oportunități
4. Setați câmpurile "Ultima intrare" și "Zile în" ca doar pentru citire
@@ -307,5 +307,5 @@ Acțiunile agentului AI consumă credite ale fluxului de lucru în funcție de m
</Note>
<Note>
Agenții AI respectă permisiunile bazate pe roluri. Puteți atribui roluri specifice agenților în **Settings → Roles** pentru a controla la ce date pot avea acces. Consultați [Permisiuni](/l/ro/user-guide/permissions-access/capabilities/permissions) pentru detalii.
Agenții AI respectă permisiunile bazate pe roluri. Puteți atribui roluri specifice agenților în **Settings → Members → Roles** pentru a controla la ce date pot avea acces. Consultați [Permisiuni](/l/ro/user-guide/permissions-access/capabilities/permissions) pentru detalii.
</Note>
@@ -8,7 +8,7 @@ description: Întrebări frecvente despre fluxurile de lucru din Twenty.
<Accordion title="De ce nu pot activa un flux de lucru?">
Este probabil o problemă de permisiuni. Aveți nevoie de acces la fluxuri de lucru pentru a le crea și activa.
**Soluție**: Contactați administratorul spațiului de lucru pentru a vă acorda acces la fluxuri de lucru în **Setări → Roluri**.
**Soluție**: Contactați administratorul spațiului de lucru pentru a vă acorda acces la fluxuri de lucru în **Setări → Membri → Roluri**.
Dacă nu vedeți deloc secțiunea Fluxuri de lucru în bara laterală, acest lucru confirmă că este o problemă de permisiuni.
</Accordion>
@@ -37,7 +37,7 @@ CRUD над записями: Люди, Компании, Сделки, ваши
Authorization: Bearer YOUR_API_KEY
```
Создайте ключ API в **Settings → API & Webhooks → + Create key**. Сразу скопируйте его — он показывается только один раз. Ключам можно задать область действия для конкретной роли в разделе **Settings → Roles → Assignment tab**, чтобы ограничить их доступ.
Создайте ключ API в **Settings → API & Webhooks → + Create key**. Сразу скопируйте его — он показывается только один раз. Ключам можно задать область действия для конкретной роли в разделе **Settings → Members → Roles → Assignment tab**, чтобы ограничить их доступ.
<VimeoEmbed videoId="928786722" title="Создание ключа API" />
@@ -88,7 +88,7 @@ Authorization: Bearer YOUR_API_KEY
Для повышения безопасности назначьте конкретную роль, чтобы ограничить доступ:
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Нажмите на роль, которую хотите назначить
3. Откройте вкладку **Назначение**
4. В разделе **Ключи API** нажмите **+ Назначить ключу API**
@@ -9,7 +9,7 @@ description: Управляйте тем, к чему агенты ИИ могу
## Назначить роль агенту ИИ
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Нажмите на роль, которую вы хотите назначить
3. Откройте вкладку **Назначение**
4. В разделе **Агенты ИИ** нажмите **+ Назначить агенту ИИ**
@@ -17,7 +17,7 @@ description: Часто задаваемые вопросы о функциях
</Accordion>
<Accordion title="Будут ли ИИ-агенты иметь доступ ко всем моим данным?">
ИИ-агенты будут работать в рамках системы разрешений. Вы можете назначать ИИ-агентам конкретные роли в **Настройки → Роли**, получая полный контроль над тем, к каким данным у них есть доступ и какие действия они могут выполнять.
ИИ-агенты будут работать в рамках системы разрешений. Вы можете назначать ИИ-агентам конкретные роли в **Настройки → Участники → Роли**, получая полный контроль над тем, к каким данным у них есть доступ и какие действия они могут выполнять.
</Accordion>
<Accordion title="Как будут работать кредиты ИИ?">
@@ -48,7 +48,7 @@ Twenty разрабатывает возможности ИИ, чтобы пом
ИИ-агенты будут управляться через существующую систему разрешений:
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Настройте, к каким данным каждый ИИ-агент может получать доступ
3. Задайте права на чтение и запись для каждого объекта
@@ -214,7 +214,7 @@ Jane,Doe,jane@widgets.co,https://widgets.co
### Настройте роли и разрешения
* Настройте роли в **Настройки → Роли**
* Настройте роли в **Настройки → Участники → Роли**
* Назначьте пользователей на соответствующие роли
### Подключите электронную почту и календарь
@@ -127,7 +127,7 @@ Acme Corp,https://acme.com,john@yourcompany.com
### Роли и разрешения
* Настройте роли в **Настройки → Роли**
* Настройте роли в **Настройки → Участники → Роли**
* Назначьте пользователям соответствующие роли
### Интеграции
@@ -13,7 +13,7 @@ description: Управляйте доступом к объектам, поля
Чтобы создать новую роль:
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. В разделе **Все роли** нажмите **+ Создать роль**
3. Введите имя роли
4. На вкладке **Разрешения** по умолчанию [настройте разрешения](#customize-permissions)
@@ -23,7 +23,7 @@ description: Управляйте доступом к объектам, поля
Чтобы удалить роль:
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Нажмите на роль, которую хотите удалить
3. Откройте вкладку **Настройки**, затем нажмите **Удалить роль**
4. Нажмите **Подтвердить** в модальном окне
@@ -36,13 +36,13 @@ description: Управляйте доступом к объектам, поля
### Просмотр текущих назначений
* Перейдите в **Настройки → Роли**
* Перейдите в **Настройки → Участники → Роли**
* Просмотрите все роли и количество назначенных им участников
* Просмотрите, какие роли у каких участников
### Назначить роль участнику
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Нажмите на роль, которую вы хотите назначить
3. Откройте вкладку **Назначение**
4. Нажмите **+ Назначить участнику**
@@ -51,7 +51,7 @@ description: Управляйте доступом к объектам, поля
### Установить роль по умолчанию
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. В разделе **Опции** найдите **Роль по умолчанию**
3. Выберите, какую роль новые участники должны получать автоматически
4. Новые участники рабочего пространства будут получать эту роль при присоединении
@@ -168,7 +168,7 @@ description: Управляйте доступом к объектам, поля
### Назначить роль ключу API
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Нажмите на роль, которую вы хотите назначить
3. Откройте вкладку **Назначение**
4. В разделе **Ключи API** нажмите **+ Назначить ключу API**
@@ -183,7 +183,7 @@ description: Управляйте доступом к объектам, поля
### Назначить роль AI-агенту
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Нажмите на роль, которую вы хотите назначить
3. Откройте вкладку **Назначение**
4. В разделе **AI-агенты** нажмите **+ Назначить AI-агенту**
@@ -19,7 +19,7 @@ description: Часто задаваемые вопросы о ролях и р
</Accordion>
<Accordion title="Как установить роль по умолчанию для новых участников?">
Перейдите в **Настройки → Роли**, найдите параметр **Роль по умолчанию** и выберите, какую роль новые участники должны автоматически получать при присоединении.
Перейдите в **Настройки → Участники → Роли**, найдите параметр **Роль по умолчанию** и выберите, какую роль новые участники должны автоматически получать при присоединении.
</Accordion>
<Accordion title="Могу ли я назначить одному пользователю несколько ролей?">
@@ -64,7 +64,7 @@ description: Часто задаваемые вопросы о ролях и р
</Accordion>
<Accordion title="Как сделать поле доступным только для чтения для отдельных пользователей?">
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Выберите роль
3. Перейдите к объекту, который содержит это поле
4. Установите для поля разрешение **Просмотр поля** (без **Редактирование поля**)
@@ -3,10 +3,12 @@ title: Настройки доменов
description: Настройте домен рабочего пространства, утверждённые домены доступа и публичные домены.
---
Настройте параметры доменов в **Настройки → Домены**.
Настройки доменов находятся в трёх местах, в зависимости от того, что вы настраиваете.
## Домен рабочей области
Настройте в **Настройки → Общие → Домен рабочего пространства**.
Измените имя своего субдомена или установите собственный домен для вашего рабочего пространства.
### Настроить домен
@@ -19,6 +21,8 @@ description: Настройте домен рабочего пространст
## Утвержденные домены
Настройте в **Настройки → Участники → Пригласить**.
Любой пользователь с адресом электронной почты в этих доменах может автоматически зарегистрироваться в этом рабочем пространстве.
### Добавить утвержденный домен доступа
@@ -35,13 +39,16 @@ description: Настройте домен рабочего пространст
## Публичные домены
Подготовьте полную и безопасную хостинг-среду на этих доменах.
Настройте в **Настройки → Приложения → Разработчик**.
Подготовьте полную и безопасную хостинг-среду на этих доменах. Публичный домен можно привязать к определённому приложению — при такой привязке только функции логики с HTTP-маршрутизацией этого приложения будут доступны на домене. Оставьте привязку пустой, чтобы открыть доступ ко всем HTTP-маршрутам рабочего пространства.
### Добавить публичный домен
1. Нажмите **Добавить публичный домен**
2. Введите домен, который вы хотите использовать
3. Настройте параметры DNS согласно инструкциям
4. Подтвердите домен
3. При желании привяжите его к приложению
4. Настройте параметры DNS согласно инструкциям
5. Подтвердите домен
SSL-сертификаты автоматически выпускаются для публичных доменов.
@@ -77,7 +77,7 @@ description: Пригласите членов команды и управля
Разрешите участникам команды присоединяться автоматически на основе домена их электронной почты:
1. Перейдите в **Настройки → Домены**
1. Перейдите в **Настройки → Участники → Пригласить**
2. Добавьте домен вашей компании (например, `yourcompany.com`)
3. Любой с таким доменом электронной почты сможет присоединиться без приглашения
@@ -137,7 +137,7 @@ description: Часто задаваемые вопросы о настройк
<AccordionGroup>
<Accordion title="Могу ли я настроить домен моего рабочего пространства?">
Да! Перейдите в **Настройки → Домены** и нажмите **Настроить домен**. У вас есть два варианта:
Да! Перейдите в **Настройки → Общие → Домен рабочего пространства** и нажмите **Настроить домен**. У вас есть два варианта:
* **Поддомен**: используйте поддомен Twenty, например `yourcompany.twenty.com`
* **Пользовательский домен**: используйте собственный домен, например `crm.yourcompany.com` (требуется настройка DNS)
@@ -146,7 +146,7 @@ description: Часто задаваемые вопросы о настройк
</Accordion>
<Accordion title="Как работают утвержденные домены доступа?">
Вы можете настроить утвержденные домены доступа, чтобы участники команды с корпоративными адресами электронной почты могли автоматически присоединяться к вашему рабочему пространству. Перейдите в **Настройки → Домены** и добавьте домен вашей компании (например, `yourcompany.com`).
Вы можете настроить утвержденные домены доступа, чтобы участники команды с корпоративными адресами электронной почты могли автоматически присоединяться к вашему рабочему пространству. Перейдите в **Настройки → Участники → Пригласить** и добавьте домен вашей компании (например, `yourcompany.com`).
</Accordion>
</AccordionGroup>
@@ -44,7 +44,7 @@ description: Настройте рабочее пространство Twenty
4. Назначьте соответствующие роли
<Note>
Прежде чем приглашать команду, проверьте роль по умолчанию в разделе **Настройки → Роли**. Новые участники автоматически получают эту роль при присоединении.
Прежде чем приглашать команду, проверьте роль по умолчанию в разделе **Настройки → Участники → Роли**. Новые участники автоматически получают эту роль при присоединении.
</Note>
## Контрольный список настроек рабочего пространства
@@ -38,7 +38,7 @@ description: Рассчитывайте и отображайте взвешен
Если вы не хотите, чтобы пользователи вручную редактировали эти вычисляемые поля:
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Выберите роль для настройки
3. Найдите объект «Сделки»
4. Установите поля **Вероятность** и **Ожидаемая сумма** как доступные только для чтения
@@ -61,7 +61,7 @@ description: Отслеживайте скорость сделок, фикси
Если вы не хотите, чтобы пользователи вручную редактировали эти вычисляемые поля:
1. Перейдите в **Настройки → Роли**
1. Перейдите в **Настройки → Участники → Роли**
2. Выберите роль для настройки
3. Найдите объект «Сделки»
4. Сделайте поля «Последний вход» и «Дней на этапе» доступными только для чтения
@@ -307,5 +307,5 @@ import { VimeoEmbed } from '/snippets/vimeo-embed.mdx';
</Note>
<Note>
ИИ-агенты соблюдают права доступа на основе ролей. Вы можете назначать агентам конкретные роли в **Настройки → Роли**, чтобы контролировать, к каким данным у них есть доступ. См. [Разрешения](/l/ru/user-guide/permissions-access/capabilities/permissions) для подробностей.
ИИ-агенты соблюдают права доступа на основе ролей. Вы можете назначать агентам конкретные роли в разделе **Настройки → Участники → Роли**, чтобы контролировать, к каким данным у них есть доступ. См. [Разрешения](/l/ru/user-guide/permissions-access/capabilities/permissions) для подробностей.
</Note>
@@ -8,7 +8,7 @@ description: Часто задаваемые вопросы о рабочих п
<Accordion title="Почему я не могу активировать рабочий процесс?">
Скорее всего, это проблема с правами доступа. Вам нужен доступ к рабочим процессам, чтобы создавать и активировать их.
**Решение**: Свяжитесь с администратором рабочего пространства, чтобы он предоставил вам доступ к рабочим процессам в **Настройки → Роли**.
**Решение**: Свяжитесь с администратором рабочего пространства, чтобы он предоставил вам доступ к рабочим процессам в разделе **Настройки → Участники → Роли**.
Если вы совсем не видите раздел "Рабочие процессы" в боковой панели, это подтверждает, что проблема в правах доступа.
</Accordion>
@@ -37,7 +37,7 @@ Her ikisi de REST ve GraphQL olarak mevcuttur. GraphQL, toplu upsert işlemleri
Authorization: Bearer YOUR_API_KEY
```
**Settings → API & Webhooks → + Create key** bölümünde bir API anahtarı oluşturun. Hemen kopyalayın — yalnızca bir kez gösterilir. Anahtarlar, erişebilecekleri alanları sınırlamak için **Settings → Roles → Assignment** sekmesi altında belirli bir role bağlanabilir.
**Settings → API & Webhooks → + Create key** bölümünde bir API anahtarı oluşturun. Hemen kopyalayın — yalnızca bir kez gösterilir. Anahtarlar, erişebilecekleri alanları sınırlamak için **Settings → Members → Roles → Assignment** sekmesi altında belirli bir role bağlanabilir.
<VimeoEmbed videoId="928786722" title="API anahtarı oluşturma" />
@@ -88,7 +88,7 @@ API anahtarınız hassas verilere erişim sağlar. Güvenilmeyen hizmetlerle pay
Daha iyi güvenlik için, erişimi sınırlamak amacıyla belirli bir rol atayın:
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Atamak istediğiniz role tıklayın
3. **Atama** sekmesini açın
4. **API Anahtarları** altında, **+ API anahtarına ata**'ya tıklayın
@@ -9,7 +9,7 @@ Yapay zekâ ajanları mevcut izin yapınıza uyar. Bu, özellikle çalışma ala
## Bir Yapay Zekâ Ajanına Rol Atama
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Atamak istediğiniz role tıklayın
3. **Atama** sekmesini açın
4. **Yapay Zekâ Ajanları** altında, **+ Yapay zekâ ajanına ata** seçeneğine tıklayın
@@ -17,7 +17,7 @@ description: Twenty'deki yapay zeka özellikleri hakkında sıkça sorulan sorul
</Accordion>
<Accordion title="Yapay zeka ajanlarının tüm verilerime erişimi olacak mı?">
Yapay zeka ajanları izin sistemi kapsamında çalışacaktır. **Ayarlar → Roller** altında yapay zeka ajanlarına belirli roller atayarak hangi verilere erişebilecekleri ve hangi işlemleri gerçekleştirebilecekleri üzerinde tam kontrol sahibi olabilirsiniz.
Yapay zeka ajanları izin sistemi kapsamında çalışacaktır. **Ayarlar → Üyeler → Roller** altında yapay zeka ajanlarına belirli roller atayarak hangi verilere erişebilecekleri ve hangi işlemleri gerçekleştirebilecekleri üzerinde tam kontrol sahibi olabilirsiniz.
</Accordion>
<Accordion title="Yapay zeka kredileri nasıl çalışacak?">
@@ -48,7 +48,7 @@ Bağlamınızı anlayan ve tüm Twenty verilerinize erişimi olan konuşmaya day
Yapay zeka ajanları mevcut izin sistemi aracılığıyla yönetilecektir:
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Her bir yapay zeka ajanının hangi verilere erişebileceğini yapılandırın
3. Nesne başına okuma/yazma izinleri belirleyin
@@ -214,7 +214,7 @@ Verileri içe aktardıktan sonra çalışma alanı yapılandırmanızı tamamlay
### Rolleri ve İzinleri Yapılandırın
* Rolleri **Ayarlar → Roller** bölümünde yapılandırın
* Rolleri **Ayarlar → Üyeler → Roller** bölümünde yapılandırın
* Kullanıcıları uygun rollere atayın
### E-posta ve Takvimi Bağlayın
@@ -127,7 +127,7 @@ Verileri içe aktardıktan sonra, aşağıdakileri manuel olarak yeniden oluştu
### Roller ve İzinler
* Rolleri **Ayarlar → Roller** bölümünde yapılandırın
* Rolleri **Ayarlar → Üyeler → Roller** bölümünde yapılandırın
* Kullanıcıları uygun rollere atayın
### Entegrasyonlar
@@ -13,7 +13,7 @@ Twenty'nin izin sistemi, üç ana alana erişimi kontrol etmenizi sağlar:
Yeni bir rol oluşturmak için:
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. **Tüm Roller** altında, **+ Rol Oluştur** seçeneğine tıklayın
3. Bir rol adı girin
4. Varsayılan **İzinler** sekmesinde, [izinleri yapılandırın](#customize-permissions)
@@ -23,7 +23,7 @@ Yeni bir rol oluşturmak için:
Bir rolü silmek için:
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Kaldırmak istediğiniz role tıklayın
3. **Ayarlar** sekmesini açın, ardından **Rolü Sil** seçeneğine tıklayın
4. Modalde **Onayla**'ya tıklayın
@@ -36,13 +36,13 @@ Bir rol silinirse, ona atanmış olan herhangi bir çalışma alanı üyesi otom
### Mevcut Atamaları Görüntüle
* **Ayarlar → Roller** bölümüne gidin
* **Ayarlar → Üyeler → Roller** bölümüne gidin
* Tüm rolleri ve her birine kaç üye atandığını görün
* Hangi üyelerin hangi rollere sahip olduğunu görün
### Bir Üyeye Rol Atama
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Atamak istediğiniz role tıklayın
3. **Atama** sekmesini açın
4. **+ Üyeye Atama**'ya tıklayın
@@ -51,7 +51,7 @@ Bir rol silinirse, ona atanmış olan herhangi bir çalışma alanı üyesi otom
### Varsayılan Rol Ayarlama
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. **Seçenekler** bölümünde, **Varsayılan Rol**'ü bulun
3. Yeni üyelerin otomatik olarak alacağı rolü seçin
4. Yeni çalışma alanı üyeleri katıldığında bu role atanacaklardır
@@ -168,7 +168,7 @@ Genel çalışma alanı aksiyonlarına erişimi kontrol edin:
### Bir API Anahtarına Rol Atama
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Atamak istediğiniz role tıklayın
3. **Atama** sekmesini açın
4. **API Anahtarları** altında, **+ API anahtarına ata**'ya tıklayın
@@ -183,7 +183,7 @@ Atanmış rolü olmayan API anahtarları varsayılan izinleri kullanır. Daha s
### Bir Yapay Zeka Ajanına Rol Atama
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Atamak istediğiniz role tıklayın
3. **Atama** sekmesini açın
4. **Yapay Zeka Ajanları** altında, **+ Yapay zeka ajanına ata**'ya tıklayın
@@ -19,7 +19,7 @@ Any workspace member assigned to that role will be automatically reassigned to t
</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.
**Ayarlar → Üyeler → Roller** bölümüne gidin, **Varsayılan Rol** seçeneğini bulun ve yeni üyeler katıldıklarında otomatik olarak hangi rolü alacaklarını seçin.
</Accordion>
<Accordion title="Can I assign multiple roles to one user?">
@@ -64,7 +64,7 @@ Row-level permissions will be available on the **Organization** plan by Q1 2026.
</Accordion>
<Accordion title="How do I make a field read-only for certain users?">
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Select the role
3. Navigate to the object containing the field
4. Set the field permission to **See Field** (without Edit Field)
@@ -3,10 +3,12 @@ title: Alan Adı Ayarları
description: Çalışma alanı alan adını, onaylanmış erişim alan adlarını ve herkese açık alan adlarını yapılandırın.
---
Alan adı ayarlarını **Ayarlar → Alan Adları** bölümünde yapılandırın.
Alan adı ayarları, neyi yapılandırdığınıza bağlı olarak üç yerde bulunur.
## İş Alanı Alan Adı
**Ayarlar → Genel → Çalışma Alanı Alan Adı** altında yapılandırın.
Alt alan adınızı düzenleyin veya çalışma alanınız için özel bir alan adı ayarlayın.
### Alan adını özelleştir
@@ -19,6 +21,8 @@ Alt alan adınızı düzenleyin veya çalışma alanınız için özel bir alan
## Onaylanmış Alan Adları
**Ayarlar → Üyeler → Davet** altında yapılandırın.
Bu alan adlarındaki bir e-posta adresine sahip olan herkes bu çalışma alanına otomatik olarak kaydolabilir.
### Onaylanmış Erişim Alanı Ekle
@@ -35,13 +39,16 @@ Bu, çalışma alanını kuruluşunuzla sınırlı tutarken tüm ekibinizin kend
## Herkese Açık Alan Adları
Bu alan adları üzerinde eksiksiz ve güvenli bir barındırma ortamı sağlayın.
**Ayarlar → Uygulamalar → Geliştirici** altında yapılandırın.
Bu alan adları üzerinde eksiksiz ve güvenli bir barındırma ortamı sağlayın. Genel bir alan adı belirli bir uygulamaya bağlanabilir — bağlandığında, yalnızca o uygulamanın HTTP üzerinden yönlendirilen mantık işlevlerine bu alan adı üzerinden erişilebilir. Çalışma alanındaki tüm HTTP rotalarını dışa açmak için ilişkilendirmeyi boş bırakın.
### Kamusal Alan Ekle
1. **Herkese Açık Alan Adı Ekle**'ye tıklayın
2. Kullanmak istediğiniz alan adını girin
3. DNS ayarlarını talimatlara uygun şekilde yapılandırın
4. Alan adını doğrulayın
3. İsteğe bağlı olarak bir uygulamaya bağlayın
4. DNS ayarlarını talimatlara uygun şekilde yapılandırın
5. Alan adını doğrulayın
Herkese açık alan adları için SSL sertifikaları otomatik olarak sağlanır.
@@ -77,7 +77,7 @@ Kabul edilmemiş davetleri yönetin:
Ekip üyelerinin e-posta alan adına göre otomatik olarak katılmasına izin verin:
1. **Ayarlar → Alan Adları** kısmına gidin
1. **Ayarlar → Üyeler → Davet** bölümüne gidin
2. Şirketinizin alan adını ekleyin (örneğin, `yourcompany.com`)
3. Bu e-posta alan adına sahip olan herkes davet olmadan katılabilir
@@ -137,7 +137,7 @@ Evet, birden fazla e-posta hesabını bağlayabilirsiniz. **Ayarlar → Hesaplar
<AccordionGroup>
<Accordion title="Çalışma alanı alan adımı özelleştirebilir miyim?">
Evet! **Ayarlar → Alanlar**'a gidin ve **Alan Adını Özelleştir**'e tıklayın. İki seçeneğiniz var:
Evet! **Ayarlar → Genel → Çalışma Alanı Alan Adı**'na gidin ve **Alan Adını Özelleştir**'e tıklayın. İki seçeneğiniz var:
* **Alt alan adı**: `yourcompany.twenty.com` gibi bir Twenty alt alan adı kullanın
* **Özel alan adı**: `crm.yourcompany.com` gibi kendi alan adınızı kullanın (DNS yapılandırması gerektirir)
@@ -146,7 +146,7 @@ Alt alan adı kurmak hızlıdır; özel alan adı ise ekibiniz için tam markal
</Accordion>
<Accordion title="Onaylı erişim alan adları nasıl çalışır?">
Şirket e-posta adreslerine sahip ekip üyelerinin çalışma alanınıza otomatik olarak katılabilmeleri için onaylı erişim alan adlarını yapılandırabilirsiniz. **Ayarlar → Alanlar**'a gidin ve şirket alan adınızı ekleyin (ör. `yourcompany.com`).
Şirket e-posta adreslerine sahip ekip üyelerinin çalışma alanınıza otomatik olarak katılabilmeleri için onaylı erişim alan adlarını yapılandırabilirsiniz. **Ayarlar → Üyeler → Davet**'e gidin ve şirket alan adınızı ekleyin (ör. `yourcompany.com`).
</Accordion>
</AccordionGroup>
@@ -44,7 +44,7 @@ E-posta ve takvim senkronizasyonunu ayarlayın:
4. Uygun rolleri atayın
<Note>
Ekibinizi davet etmeden önce, **Ayarlar → Roller** altında varsayılan rolü kontrol edin. Yeni üyeler katıldıklarında otomatik olarak bu role atanır.
Ekibinizi davet etmeden önce, **Ayarlar → Üyeler → Roller** altında varsayılan rolü kontrol edin. Yeni üyeler katıldıklarında otomatik olarak bu role atanır.
</Note>
## Çalışma Alanı Ayarları Kontrol Listesi
@@ -38,7 +38,7 @@ Fırsatlar nesnesinde iki özel alana ihtiyacınız var.
Kullanıcıların bu hesaplanan alanları manuel olarak düzenlemesini istemiyorsanız:
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Yapılandırılacak rolü seçin
3. Fırsatlar nesnesini bulun
4. **Olasılık** ve **Beklenen Tutar** alanlarını salt okunur yapın
@@ -61,7 +61,7 @@ Closed Won ve Closed Lost için "Days in" alanlarına ihtiyaç yoktur; çünkü
Bu hesaplanan alanların kullanıcılar tarafından manuel olarak düzenlenmesini istemiyorsanız:
1. **Ayarlar → Roller** bölümüne gidin
1. **Ayarlar → Üyeler → Roller** bölümüne gidin
2. Yapılandırılacak rolü seçin
3. Fırsatlar nesnesini bulun
4. "Last Entered" ve "Days in" alanlarını salt okunur yapın
@@ -307,5 +307,5 @@ Yapay Zeka Aracısı eylemleri, kullanılan yapay zeka modeline bağlı olarak i
</Note>
<Note>
Yapay zeka aracıları role dayalı izinlere uyar. **Ayarlar → Roller** altında aracılara hangi verilere erişebileceklerini kontrol etmek için belirli roller atayabilirsiniz. Ayrıntılar için [İzinler](/l/tr/user-guide/permissions-access/capabilities/permissions) bölümüne bakın.
Yapay zeka aracıları role dayalı izinlere uyar. Temsilcilerin hangi verilere erişebileceklerini kontrol etmek için **Ayarlar → Üyeler → Roller** altında temsilcilere belirli roller atayabilirsiniz. Ayrıntılar için [İzinler](/l/tr/user-guide/permissions-access/capabilities/permissions) bölümüne bakın.
</Note>
@@ -8,7 +8,7 @@ description: Twenty'deki iş akışları hakkında sıkça sorulan sorular.
<Accordion title="Bir iş akışını neden etkinleştiremiyorum?">
Bu muhtemelen bir yetki sorunudur. İş akışlarını oluşturmak ve etkinleştirmek için iş akışlarına erişiminiz olmalıdır.
**Çözüm**: **Ayarlar → Roller** altında size iş akışı erişimi vermesi için çalışma alanı yöneticinizle iletişime geçin.
**Çözüm**: **Ayarlar → Üyeler → Roller** altında size iş akışı erişimi vermesi için çalışma alanı yöneticinizle iletişime geçin.
Kenar çubuğunuzda İş Akışları bölümünü hiç görmüyorsanız, bunun bir yetki sorunu olduğunu doğrular.
</Accordion>
@@ -37,7 +37,7 @@ Twenty 没有静态 API 参考文档。 每个工作区都有自己的架构—
Authorization: Bearer YOUR_API_KEY
```
在 **Settings → API & Webhooks → + Create key** 中创建 API 密钥。 请立即复制——仅显示一次。 可在 **Settings → Roles → Assignment 选项卡** 下将密钥限定到特定角色,以限制其可访问的范围。
在 **Settings → API & Webhooks → + Create key** 中创建 API 密钥。 请立即复制——仅显示一次。 可在 **Settings → Members → Roles → Assignment 选项卡** 下将密钥限定到特定角色,以限制其可访问的范围。
<VimeoEmbed videoId="928786722" title="创建 API 密钥" />

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