Compare commits

..

2 Commits

Author SHA1 Message Date
Weiko 24b074f436 fix 2026-03-11 15:32:57 +01:00
Weiko 181b48105e RLS: Allow Relation predicates other than workspace member 2026-03-11 14:16:53 +01:00
2960 changed files with 69905 additions and 82315 deletions
+18
View File
@@ -0,0 +1,18 @@
{
"install": "curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash - && sudo apt-get install -y nodejs && node --version && yarn install && echo 'Setting up Docker Compose environment...' && cd packages/twenty-docker && cp -n docker-compose.yml docker-compose.dev.yml || true && echo 'Dependencies installed and docker-compose prepared'",
"start": "sudo service docker start && echo 'Docker service started' && cd packages/twenty-docker && echo 'Installing yq for YAML processing...' && sudo apt-get update -qq && sudo apt-get install -y wget && wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 && sudo chmod +x /usr/local/bin/yq && echo 'Patching docker-compose for local development...' && yq eval 'del(.services.server.image)' -i docker-compose.dev.yml && yq eval '.services.server.build.context = \"../../\"' -i docker-compose.dev.yml && yq eval '.services.server.build.dockerfile = \"./packages/twenty-docker/twenty/Dockerfile\"' -i docker-compose.dev.yml && yq eval 'del(.services.worker.image)' -i docker-compose.dev.yml && yq eval '.services.worker.build.context = \"../../\"' -i docker-compose.dev.yml && yq eval '.services.worker.build.dockerfile = \"./packages/twenty-docker/twenty/Dockerfile\"' -i docker-compose.dev.yml && echo 'Setting up .env file with database configuration...' && echo 'SERVER_URL=http://localhost:3000' > .env && echo 'APP_SECRET='$(openssl rand -base64 32) >> .env && echo 'PG_DATABASE_PASSWORD='$(openssl rand -hex 16) >> .env && echo 'PG_DATABASE_URL=postgres://postgres:password@localhost:5432/postgres' >> .env && echo 'SIGN_IN_PREFILLED=true' >> .env && echo 'Building and starting services...' && docker-compose -f docker-compose.dev.yml up -d --build && echo 'Waiting for services to initialize...' && sleep 30 && echo 'Checking service health...' && docker-compose -f docker-compose.dev.yml ps && echo 'Environment setup complete!'",
"terminals": [
{
"name": "Database Setup & Seed",
"command": "sleep 40 && cd packages/twenty-docker && echo 'Waiting for PostgreSQL to be ready...' && until docker-compose -f docker-compose.dev.yml exec -T db pg_isready -U postgres; do echo 'Waiting for PostgreSQL...'; sleep 5; done && echo 'PostgreSQL is ready!' && echo 'Waiting for Twenty server to be healthy...' && until docker-compose -f docker-compose.dev.yml exec -T server curl --fail http://localhost:3000/healthz 2>/dev/null; do echo 'Waiting for server...'; sleep 5; done && echo 'Server is healthy!' && echo 'Running database setup and seeding...' && docker-compose -f docker-compose.dev.yml exec -T server npx nx database:reset twenty-server && echo 'Database seeded successfully!' && bash"
},
{
"name": "Application Logs",
"command": "sleep 35 && cd packages/twenty-docker && echo 'Following application logs...' && docker-compose -f docker-compose.dev.yml logs -f server worker"
},
{
"name": "Service Monitor",
"command": "sleep 15 && cd packages/twenty-docker && echo '=== Service Status Monitor ===' && while true; do clear; echo '=== Service Status at $(date) ===' && docker-compose -f docker-compose.dev.yml ps && echo '\\n=== Health Status ===' && (docker-compose -f docker-compose.dev.yml exec -T server curl -s http://localhost:3000/healthz 2>/dev/null && echo '✅ Twenty Server: Healthy') || echo '❌ Twenty Server: Not Ready' && (docker-compose -f docker-compose.dev.yml exec -T db pg_isready -U postgres 2>/dev/null && echo '✅ PostgreSQL: Ready') || echo '❌ PostgreSQL: Not Ready' && echo '\\n=== Database Connection Test ===' && docker-compose -f docker-compose.dev.yml exec -T server node -e \"const { Client } = require('pg'); const client = new Client({connectionString: process.env.PG_DATABASE_URL}); client.connect().then(() => {console.log('✅ Database Connection: OK'); client.end();}).catch(e => console.log('❌ Database Connection: Failed -', e.message));\" || echo 'Connection test failed' && sleep 45; done"
}
]
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"install": "yarn install",
"start": "(sudo service docker start || service docker start || true) && bash packages/twenty-utils/setup-dev-env.sh && npx nx database:reset twenty-server",
"start": "sudo service docker start && sleep 2 && (docker start twenty_pg 2>/dev/null || make -C packages/twenty-docker postgres-on-docker) && (docker start twenty_redis 2>/dev/null || make -C packages/twenty-docker redis-on-docker) && until docker exec twenty_pg pg_isready -U postgres -h localhost 2>/dev/null; do sleep 1; done && echo 'PostgreSQL ready' && until docker exec twenty_redis redis-cli ping 2>/dev/null | grep -q PONG; do sleep 1; done && echo 'Redis ready' && bash packages/twenty-utils/setup-dev-env.sh && npx nx database:reset twenty-server",
"terminals": [
{
"name": "Development Server",
+1 -1
View File
@@ -1,5 +1,5 @@
.git
.env
**/node_modules
node_modules
.nx/cache
packages/twenty-server/.env
-19
View File
@@ -1,19 +0,0 @@
storage: /tmp/verdaccio-storage
auth:
htpasswd:
file: /tmp/verdaccio-htpasswd
max_users: 100
uplinks:
npmjs:
url: https://registry.npmjs.org/
packages:
'twenty-sdk':
access: $all
publish: $all
'create-twenty-app':
access: $all
publish: $all
'**':
access: $all
proxy: npmjs
log: { type: stdout, format: pretty, level: warn }
-184
View File
@@ -1,184 +0,0 @@
name: CI Create App E2E
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
changed-files-check:
uses: ./.github/workflows/changed-files.yaml
with:
files: |
packages/create-twenty-app/**
packages/twenty-sdk/**
packages/twenty-shared/**
packages/twenty-server/**
!packages/create-twenty-app/package.json
!packages/twenty-sdk/package.json
!packages/twenty-shared/package.json
!packages/twenty-server/package.json
create-app-e2e:
needs: changed-files-check
if: needs.changed-files-check.outputs.any_changed == 'true'
timeout-minutes: 30
runs-on: ubuntu-latest-4-cores
services:
postgres:
image: twentycrm/twenty-postgres-spilo
env:
PGUSER_SUPERUSER: postgres
PGPASSWORD_SUPERUSER: postgres
ALLOW_NOSSL: 'true'
SPILO_PROVIDER: 'local'
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis
ports:
- 6379:6379
steps:
- name: Fetch custom Github Actions and base branch history
uses: actions/checkout@v4
with:
fetch-depth: 10
- name: Install dependencies
uses: ./.github/actions/yarn-install
- name: Set CI version and prepare packages for publish
run: |
CI_VERSION="0.0.0-ci.$(date +%s)"
echo "CI_VERSION=$CI_VERSION" >> $GITHUB_ENV
npx nx run-many -t set-local-version -p twenty-sdk create-twenty-app --releaseVersion=$CI_VERSION
- name: Build packages
run: |
npx nx build twenty-sdk
npx nx build create-twenty-app
- name: Install and start Verdaccio
run: |
npx verdaccio --config .github/verdaccio-config.yaml &
for i in $(seq 1 30); do
if curl -s http://localhost:4873 > /dev/null 2>&1; then
echo "Verdaccio is ready"
break
fi
echo "Waiting for Verdaccio... ($i/30)"
sleep 1
done
- name: Publish packages to local registry
run: |
npm set //localhost:4873/:_authToken "ci-auth-token"
for pkg in twenty-sdk create-twenty-app; do
cd packages/$pkg
npm publish --registry http://localhost:4873 --tag ci
cd ../..
done
- name: Scaffold app using published create-twenty-app
run: |
npm install -g create-twenty-app@$CI_VERSION --registry http://localhost:4873
create-twenty-app --version
mkdir -p /tmp/e2e-test-workspace
cd /tmp/e2e-test-workspace
create-twenty-app test-app --exhaustive --display-name "Test App" --description "E2E test app" --skip-local-instance
- name: Install scaffolded app dependencies
run: |
cd /tmp/e2e-test-workspace/test-app
echo 'npmRegistryServer: "http://localhost:4873"' >> .yarnrc.yml
echo 'unsafeHttpWhitelist: ["localhost"]' >> .yarnrc.yml
YARN_ENABLE_IMMUTABLE_INSTALLS=false yarn install --no-immutable
- name: Verify installed app versions
run: |
cd /tmp/e2e-test-workspace/test-app
echo "--- Checking package.json references correct SDK version ---"
node -e "
const pkg = require('./package.json');
const sdkVersion = pkg.devDependencies['twenty-sdk'];
if (!sdkVersion.startsWith('0.0.0-ci.')) {
console.error('Expected twenty-sdk version to start with 0.0.0-ci., got:', sdkVersion);
process.exit(1);
}
console.log('SDK version in scaffolded app:', sdkVersion);
"
- name: Verify SDK CLI is available
run: |
cd /tmp/e2e-test-workspace/test-app
npx --no-install twenty --version
- name: Setup server environment
run: npx nx reset:env:e2e-testing-server twenty-server
- name: Build server
run: npx nx build twenty-server
- name: Create and setup database
run: |
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "default";'
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";'
npx nx run twenty-server:database:reset
- name: Start server
run: |
npx nx start twenty-server &
echo "Waiting for server to be ready..."
timeout 60 bash -c 'until curl -s http://localhost:3000/health; do sleep 2; done'
- name: Authenticate with twenty-server
env:
SEED_API_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ1c2VySWQiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtNDYzZi00MzViLTgyOGMtMTA3ZTAwN2EyNzExIiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWU3Yy00M2Q5LWE1ZGItNjg1YjUwNjlkODE2IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjIwNjY4NTc3MDR9.HMGqCsVlOAPVUBhKSGlD1X86VoHKt4LIUtET3CGIdik'
run: |
cd /tmp/e2e-test-workspace/test-app
npx --no-install twenty remote add --token $SEED_API_KEY --url http://localhost:3000
- name: Build scaffolded app
run: |
cd /tmp/e2e-test-workspace/test-app
npx --no-install twenty build
test -d .twenty/output
- name: Execute hello-world logic function
run: |
cd /tmp/e2e-test-workspace/test-app
EXEC_OUTPUT=$(npx --no-install twenty exec --functionName hello-world-logic-function)
echo "$EXEC_OUTPUT"
echo "$EXEC_OUTPUT" | grep -q "Hello, World!"
- name: Run scaffolded app integration test
env:
TWENTY_API_URL: http://localhost:3000
run: |
cd /tmp/e2e-test-workspace/test-app
yarn test
ci-create-app-e2e-status-check:
if: always() && !cancelled()
timeout-minutes: 5
runs-on: ubuntu-latest
needs: [changed-files-check, create-app-e2e]
steps:
- name: Fail job if any needs failed
if: contains(needs.*.result, 'failure')
run: exit 1
+2 -2
View File
@@ -10,8 +10,8 @@ permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
group: ${{ github.workflow }}-${{ github.event_name == 'merge_group' && github.event.merge_group.base_ref || github.ref }}
cancel-in-progress: ${{ github.event_name != 'merge_group' }}
jobs:
e2e-test:
+3 -3
View File
@@ -40,8 +40,7 @@ jobs:
uses: actions/checkout@v4
with:
token: ${{ github.token }}
repository: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
ref: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
- name: Install dependencies
uses: ./.github/actions/yarn-install
@@ -112,7 +111,7 @@ jobs:
run: yarn docs:generate-paths
- name: Commit artifacts to pull request branch
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
if: github.event_name == 'pull_request'
run: |
git add packages/twenty-docs/docs.json packages/twenty-docs/navigation/navigation.template.json packages/twenty-shared/src/constants/DocumentationPaths.ts
if git diff --staged --quiet --exit-code; then
@@ -150,3 +149,4 @@ jobs:
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+4 -13
View File
@@ -188,22 +188,13 @@ IMPORTANT: Use Context7 for code generation, setup or configuration steps, or li
- Descriptive test names: "should [behavior] when [condition]"
- Clear mocks between tests with `jest.clearAllMocks()`
## Dev Environment Setup
## CI Environment (GitHub Actions)
All dev environments (Claude Code web, Cursor, local) use one script:
When running in CI, the dev environment is **not** pre-configured. Dependencies are installed but builds, env files, and databases are not set up.
```bash
bash packages/twenty-utils/setup-dev-env.sh
```
This handles everything: starts Postgres + Redis (auto-detects local services vs Docker), creates databases, and copies `.env` files. Idempotent — safe to run multiple times.
- `--docker` — force Docker mode (uses `packages/twenty-docker/docker-compose.dev.yml`)
- `--down` — stop services
- `--reset` — wipe data and restart fresh
- **Before running tests, builds, lint, type checks, or DB operations**, run: `bash packages/twenty-utils/setup-dev-env.sh`
- **Skip the setup script** for tasks that only read code — architecture questions, code review, documentation, etc.
**Note:** CI workflows (GitHub Actions) manage services via Actions service containers and run setup steps individually — they don't use this script.
- The script is idempotent and safe to run multiple times.
## Important Files
- `nx.json` - Nx workspace configuration with task definitions
+3 -3
View File
@@ -25,8 +25,8 @@
# Installation
See:
🚀 [Self-hosting](https://docs.twenty.com/developers/self-host/capabilities/docker-compose)
🖥️ [Local Setup](https://docs.twenty.com/developers/contribute/capabilities/local-setup)
🚀 [Self-hosting](https://docs.twenty.com/developers/self-hosting/docker-compose)
🖥️ [Local Setup](https://docs.twenty.com/developers/local-setup)
# Why Twenty
@@ -36,7 +36,7 @@ We built Twenty for three reasons:
**A fresh start is required to build a better experience.** We can learn from past mistakes and craft a cohesive experience inspired by new UX patterns from tools like Notion, Airtable or Linear.
**We believe in open-source and community.** Hundreds of developers are already building Twenty together. Once we have plugin capabilities, a whole ecosystem will grow around it.
**We believe in Open-source and community.** Hundreds of developers are already building Twenty together. Once we have plugin capabilities, a whole ecosystem will grow around it.
<br />
-8
View File
@@ -136,14 +136,6 @@
"cache": true,
"dependsOn": ["^build"]
},
"set-local-version": {
"executor": "nx:run-commands",
"cache": false,
"options": {
"cwd": "{projectRoot}",
"command": "npm pkg set version={args.releaseVersion}"
}
},
"storybook:build": {
"executor": "nx:run-commands",
"cache": true,
+2 -2
View File
@@ -1,7 +1,7 @@
{
"private": true,
"dependencies": {
"@apollo/client": "^4.0.0",
"@apollo/client": "^3.7.17",
"@floating-ui/react": "^0.24.3",
"@linaria/core": "^6.2.0",
"@linaria/react": "^6.2.1",
@@ -164,7 +164,6 @@
"tsc-alias": "^1.8.16",
"tsconfig-paths": "^4.2.0",
"tsx": "^4.17.0",
"verdaccio": "^6.3.1",
"vite": "^7.0.0",
"vitest": "^4.0.18"
},
@@ -207,6 +206,7 @@
"packages/twenty-e2e-testing",
"packages/twenty-shared",
"packages/twenty-sdk",
"packages/twenty-standard-application",
"packages/twenty-apps",
"packages/twenty-cli",
"packages/create-twenty-app",
+33 -65
View File
@@ -25,47 +25,41 @@ See Twenty application documentation https://docs.twenty.com/developers/extend/c
## Prerequisites
- Node.js 24+ (recommended) and Yarn 4
- Docker (for the local Twenty dev server)
- A Twenty workspace and an API key (create one at https://app.twenty.com/settings/api-webhooks)
## Quick start
```bash
# Scaffold a new app — the CLI will offer to start a local Twenty server
npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
# The scaffolder can automatically:
# 1. Start a local Twenty server (Docker)
# 2. Open the browser to log in (tim@apple.dev / tim@apple.dev)
# 3. Authenticate your app via OAuth
# Get help and list all available commands
yarn twenty help
# Or do it manually:
yarn twenty server start # Start local Twenty server
yarn twenty remote add --local # Authenticate via OAuth
# Authenticate using your API key (you'll be prompted)
yarn twenty auth:login
# Add a new entity to your application (guided)
yarn twenty entity:add
# Start dev mode: watches, builds, and syncs local changes to your workspace
yarn twenty dev
# (also auto-generates typed CoreApiClient — MetadataApiClient ships pre-built with the SDK — both available via `twenty-sdk/clients`)
yarn twenty app:dev
# Watch your application's function logs
yarn twenty logs
yarn twenty function:logs
# Execute a function with a JSON payload
yarn twenty exec -n my-function -p '{"key": "value"}'
yarn twenty function:execute -n my-function -p '{"key": "value"}'
# Execute the pre-install function
yarn twenty exec --preInstall
yarn twenty function:execute --preInstall
# Execute the post-install function
yarn twenty exec --postInstall
# Build the app for distribution
yarn twenty build
# Publish the app to npm or directly to a Twenty server
yarn twenty publish
yarn twenty function:execute --postInstall
# Uninstall the application from the current workspace
yarn twenty uninstall
yarn twenty app:uninstall
```
## Scaffolding modes
@@ -107,69 +101,43 @@ npx create-twenty-app@latest my-app -m
- `skills/example-skill.ts` — Example AI agent skill definition
- `__tests__/app-install.integration-test.ts` — Integration test that builds, installs, and verifies the app (includes `vitest.config.ts`, `tsconfig.spec.json`, and a setup file)
## Local server
The scaffolder can start a local Twenty dev server for you (all-in-one Docker image with PostgreSQL, Redis, server, and worker). You can also manage it manually:
```bash
yarn twenty server start # Start (pulls image if needed)
yarn twenty server status # Check if it's healthy
yarn twenty server logs # Stream logs
yarn twenty server stop # Stop (data is preserved)
yarn twenty server reset # Wipe all data and start fresh
```
The server is pre-seeded with a workspace and user (`tim@apple.dev` / `tim@apple.dev`).
## Next steps
- Run `yarn twenty help` to see all available commands.
- Use `yarn twenty remote add --local` to authenticate with your Twenty workspace via OAuth.
- Explore the generated project and add your first entity with `yarn twenty add` (logic functions, front components, objects, roles, views, navigation menu items, skills).
- Use `yarn twenty dev` while you iterate — it watches, builds, and syncs changes to your workspace in real time.
- `CoreApiClient` (for workspace data via `/graphql`) is auto-generated by `yarn twenty dev`. `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built with the SDK. Both are available via `import { CoreApiClient, MetadataApiClient } from 'twenty-sdk/clients'`.
- Use `yarn twenty auth:login` to authenticate with your Twenty workspace.
- Explore the generated project and add your first entity with `yarn twenty entity:add` (logic functions, front components, objects, roles, views, navigation menu items, skills).
- Use `yarn twenty app:dev` while you iterate — it watches, builds, and syncs changes to your workspace in real time.
- `CoreApiClient` (for workspace data via `/graphql`) is auto-generated by `yarn twenty app:dev`. `MetadataApiClient` (for workspace configuration and file uploads via `/metadata`) ships pre-built with the SDK. Both are available via `import { CoreApiClient, MetadataApiClient } from 'twenty-sdk/clients'`.
## Build and publish your application
## Publish your application
Once your app is ready, build and publish it using the CLI:
```bash
# Build the app (output goes to .twenty/output/)
yarn twenty build
# Build and create a tarball (.tgz) for distribution
yarn twenty build --tarball
# Publish to npm (requires npm login)
yarn twenty publish
# Publish with a dist-tag (e.g. beta, next)
yarn twenty publish --tag beta
# Deploy directly to a Twenty server (builds, uploads, and installs in one step)
yarn twenty deploy
```
### Publish to the Twenty marketplace
You can also contribute your application to the curated marketplace:
Applications are currently stored in `twenty/packages/twenty-apps`.
You can share your application with all Twenty users:
```bash
# pull the Twenty project
git clone https://github.com/twentyhq/twenty.git
cd twenty
# create a new branch
git checkout -b feature/my-awesome-app
```
- Copy your app folder into `twenty/packages/twenty-apps`.
- Commit your changes and open a pull request on https://github.com/twentyhq/twenty
```bash
git commit -m "Add new application"
git push
```
Our team reviews contributions for quality, security, and reusability before merging.
## Troubleshooting
- Server not starting: check Docker is running (`docker info`), then try `yarn twenty server logs`.
- Auth not working: make sure you're logged in to Twenty in the browser first, then run `yarn twenty remote add --local`.
- Types not generated: ensure `yarn twenty dev` is running — it auto-generates the typed client.
- Auth prompts not appearing: run `yarn twenty auth:login` again and verify the API key permissions.
- Types not generated: ensure `yarn twenty app:dev` is running — it autogenerates the typed client.
## Contributing
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "create-twenty-app",
"version": "0.8.0-canary.1",
"version": "0.7.0-canary.0",
"description": "Command-line interface to create Twenty application",
"main": "dist/cli.cjs",
"bin": "dist/cli.cjs",
-1
View File
@@ -24,7 +24,6 @@
"command": "node dist/cli.cjs"
}
},
"set-local-version": {},
"typecheck": {},
"lint": {},
"test": {
+1 -30
View File
@@ -18,19 +18,6 @@ const program = new Command(packageJson.name)
'-m, --minimal',
'Create only core entities (application-config and default-role)',
)
.option('-n, --name <name>', 'Application name (skips prompt)')
.option(
'-d, --display-name <displayName>',
'Application display name (skips prompt)',
)
.option(
'--description <description>',
'Application description (skips prompt)',
)
.option(
'--skip-local-instance',
'Skip the local Twenty instance setup prompt',
)
.helpOption('-h, --help', 'Display this help message.')
.action(
async (
@@ -38,10 +25,6 @@ const program = new Command(packageJson.name)
options?: {
exhaustive?: boolean;
minimal?: boolean;
name?: string;
displayName?: string;
description?: string;
skipLocalInstance?: boolean;
},
) => {
const modeFlags = [options?.exhaustive, options?.minimal].filter(Boolean);
@@ -64,21 +47,9 @@ const program = new Command(packageJson.name)
process.exit(1);
}
if (options?.name !== undefined && options.name.trim().length === 0) {
console.error(chalk.red('Error: --name cannot be empty.'));
process.exit(1);
}
const mode: ScaffoldingMode = options?.minimal ? 'minimal' : 'exhaustive';
await new CreateAppCommand().execute({
directory,
mode,
name: options?.name,
displayName: options?.displayName,
description: options?.description,
skipLocalInstance: options?.skipLocalInstance,
});
await new CreateAppCommand().execute(directory, mode);
},
);
@@ -11,4 +11,3 @@
- Creating an object without an index view associated. Unless this is a technical object, user will need to visualize it.
- Creating a view without a navigationMenuItem associated. This will make the view available on the left sidebar.
- Creating a front-end component that has a scroll instead of being responsive to its fixed widget height and width, unless it is specifically meant to be used in a canvas tab.
@@ -1,11 +1,62 @@
This is a [Twenty](https://twenty.com) application bootstrapped with [`create-twenty-app`](https://www.npmjs.com/package/create-twenty-app).
This is a [Twenty](https://twenty.com) application project bootstrapped with [`create-twenty-app`](https://www.npmjs.com/package/create-twenty-app).
## Getting Started
Run `yarn twenty help` to list all available commands.
First, authenticate to your workspace:
```bash
yarn twenty auth:login
```
Then, start development mode to sync your app and watch for changes:
```bash
yarn twenty app:dev
```
Open your Twenty instance and go to `/settings/applications` section to see the result.
## Available Commands
Run `yarn twenty help` to list all available commands. Common commands:
```bash
# Authentication
yarn twenty auth:login # Authenticate with Twenty
yarn twenty auth:logout # Remove credentials
yarn twenty auth:status # Check auth status
yarn twenty auth:switch # Switch default workspace
yarn twenty auth:list # List all configured workspaces
# Application
yarn twenty app:dev # Start dev mode (watch, build, sync, and auto-generate typed client)
yarn twenty entity:add # Add a new entity (object, field, function, front-component, role, view, navigation-menu-item)
yarn twenty function:logs # Stream function logs
yarn twenty function:execute # Execute a function with JSON payload
yarn twenty app:uninstall # Uninstall app from workspace
```
## Integration Tests
If your project includes the example integration test (`src/__tests__/app-install.integration-test.ts`), you can run it with:
```bash
# Make sure a Twenty server is running at http://localhost:3000
yarn test
```
The test builds and installs the app, then verifies it appears in the applications list. Test configuration (API URL and API key) is defined in `vitest.config.ts`.
## LLMs instructions
Main docs and pitfalls are available in LLMS.md file.
## Learn More
- [Twenty Apps documentation](https://docs.twenty.com/developers/extend/capabilities/apps)
- [twenty-sdk CLI reference](https://www.npmjs.com/package/twenty-sdk)
- [Discord](https://discord.gg/cx5n4Jzs57)
To learn more about Twenty applications, take a look at the following resources:
- [twenty-sdk](https://www.npmjs.com/package/twenty-sdk) - learn about `twenty-sdk` tool.
- [Twenty doc](https://docs.twenty.com/) - Twenty's documentation.
- Join our [Discord](https://discord.gg/cx5n4Jzs57)
You can check out [the Twenty GitHub repository](https://github.com/twentyhq/twenty) - your feedback and contributions are welcome!
@@ -1,18 +1,12 @@
import { copyBaseApplicationProject } from '@/utils/app-template';
import { convertToLabel } from '@/utils/convert-to-label';
import { install } from '@/utils/install';
import {
type LocalInstanceResult,
setupLocalInstance,
} from '@/utils/setup-local-instance';
import { tryGitInit } from '@/utils/try-git-init';
import chalk from 'chalk';
import * as fs from 'fs-extra';
import inquirer from 'inquirer';
import kebabCase from 'lodash.kebabcase';
import { execSync } from 'node:child_process';
import * as path from 'path';
import { isDefined } from 'twenty-shared/utils';
import {
type ExampleOptions,
@@ -21,24 +15,16 @@ import {
const CURRENT_EXECUTION_DIRECTORY = process.env.INIT_CWD || process.cwd();
type CreateAppOptions = {
directory?: string;
mode?: ScaffoldingMode;
name?: string;
displayName?: string;
description?: string;
skipLocalInstance?: boolean;
};
export class CreateAppCommand {
async execute(options: CreateAppOptions = {}): Promise<void> {
async execute(
directory?: string,
mode: ScaffoldingMode = 'exhaustive',
): Promise<void> {
try {
const { appName, appDisplayName, appDirectory, appDescription } =
await this.getAppInfos(options);
await this.getAppInfos(directory);
const exampleOptions = this.resolveExampleOptions(
options.mode ?? 'exhaustive',
);
const exampleOptions = this.resolveExampleOptions(mode);
await this.validateDirectory(appDirectory);
@@ -46,7 +32,6 @@ export class CreateAppCommand {
await fs.ensureDir(appDirectory);
console.log(chalk.gray(' Scaffolding project files...'));
await copyBaseApplicationProject({
appName,
appDisplayName,
@@ -55,24 +40,11 @@ export class CreateAppCommand {
exampleOptions,
});
console.log(chalk.gray(' Installing dependencies...'));
await install(appDirectory);
console.log(chalk.gray(' Initializing git repository...'));
await tryGitInit(appDirectory);
let localResult: LocalInstanceResult = { running: false };
if (!options.skipLocalInstance) {
// Auto-detect a running server first
localResult = await setupLocalInstance(appDirectory);
if (localResult.running && localResult.serverUrl) {
await this.connectToLocal(appDirectory, localResult.serverUrl);
}
}
this.logSuccess(appDirectory, localResult);
this.logSuccess(appDirectory);
} catch (error) {
console.error(
chalk.red('Initialization failed:'),
@@ -82,25 +54,19 @@ export class CreateAppCommand {
}
}
private async getAppInfos(options: CreateAppOptions): Promise<{
private async getAppInfos(directory?: string): Promise<{
appName: string;
appDisplayName: string;
appDescription: string;
appDirectory: string;
}> {
const { directory } = options;
const hasName = isDefined(options.name) || isDefined(directory);
const hasDisplayName = isDefined(options.displayName);
const hasDescription = isDefined(options.description);
const { name, displayName, description } = await inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'Application name:',
when: () => !hasName,
default: 'my-twenty-app',
when: () => !directory,
default: 'my-awesome-app',
validate: (input) => {
if (input.length === 0) return 'Application name is required';
return true;
@@ -110,33 +76,25 @@ export class CreateAppCommand {
type: 'input',
name: 'displayName',
message: 'Application display name:',
when: () => !hasDisplayName,
default: (answers: { name?: string }) => {
return convertToLabel(
answers?.name ?? options.name ?? directory ?? '',
);
default: (answers: any) => {
return convertToLabel(answers?.name ?? directory);
},
},
{
type: 'input',
name: 'description',
message: 'Application description (optional):',
when: () => !hasDescription,
default: '',
},
]);
const appName = (
options.name ??
name ??
directory ??
'my-twenty-app'
).trim();
const computedName = name ?? directory;
const appDisplayName =
(options.displayName ?? displayName)?.trim() || convertToLabel(appName);
const appName = computedName.trim();
const appDescription = (options.description ?? description ?? '').trim();
const appDisplayName = displayName.trim();
const appDescription = description.trim();
const appDirectory = directory
? path.join(CURRENT_EXECUTION_DIRECTORY, directory)
@@ -193,55 +151,22 @@ export class CreateAppCommand {
appDirectory: string;
appName: string;
}): void {
console.log(chalk.blue('Creating Twenty Application'));
console.log(chalk.gray(` Directory: ${appDirectory}`));
console.log(chalk.gray(` Name: ${appName}`));
console.log(chalk.blue('🎯 Creating Twenty Application'));
console.log(chalk.gray(`📁 Directory: ${appDirectory}`));
console.log(chalk.gray(`📝 Name: ${appName}`));
console.log('');
}
private async connectToLocal(
appDirectory: string,
serverUrl: string,
): Promise<void> {
try {
execSync(
`npx nx run twenty-sdk:start -- remote add ${serverUrl} --as local`,
{
cwd: appDirectory,
stdio: 'inherit',
},
);
console.log(chalk.green('Authenticated with local Twenty instance.'));
} catch {
console.log(
chalk.yellow(
'Authentication skipped. Run `npx nx run twenty-sdk:start -- remote add --local` manually.',
),
);
}
}
private logSuccess(
appDirectory: string,
localResult: LocalInstanceResult,
): void {
private logSuccess(appDirectory: string): void {
const dirName = appDirectory.split('/').reverse()[0] ?? '';
console.log(chalk.green('Application created!'));
console.log(chalk.green('Application created!'));
console.log('');
console.log(chalk.blue('Next steps:'));
console.log(chalk.gray(` cd ${dirName}`));
if (!localResult.running) {
console.log(
chalk.gray(
' yarn twenty remote add --local # Authenticate with Twenty',
),
);
}
console.log(
chalk.gray(' yarn twenty dev # Start dev mode'),
chalk.gray(' yarn twenty auth:login # Authenticate with Twenty'),
);
console.log(chalk.gray(' yarn twenty app:dev # Start dev mode'));
}
}
@@ -103,6 +103,7 @@ describe('scaffoldIntegrationTest', () => {
expect(content).toContain('TWENTY_API_KEY');
expect(content).not.toContain('TWENTY_TEST_API_KEY');
expect(content).toContain('TWENTY_API_URL');
expect(content).toContain('setup-test.ts');
expect(content).toContain('tsconfig.spec.json');
expect(content).toContain('integration-test.ts');
@@ -30,12 +30,12 @@ export const copyBaseApplicationProject = async ({
includeExampleIntegrationTest: exampleOptions.includeExampleIntegrationTest,
});
await createYarnLock(appDirectory);
await createGitignore(appDirectory);
await createPublicAssetDirectory(appDirectory);
await createYarnLock(appDirectory);
const sourceFolderPath = join(appDirectory, SRC_FOLDER);
await fs.ensureDir(sourceFolderPath);
@@ -142,6 +142,13 @@ const createPublicAssetDirectory = async (appDirectory: string) => {
await fs.ensureDir(join(appDirectory, ASSETS_DIR));
};
const createYarnLock = async (appDirectory: string) => {
const yarnLockContent = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
`;
await fs.writeFile(join(appDirectory, 'yarn.lock'), yarnLockContent);
};
const createGitignore = async (appDirectory: string) => {
const gitignoreContent = `# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
@@ -474,7 +481,7 @@ const createExampleNavigationMenuItem = async ({
const universalIdentifier = v4();
const content = `import { defineNavigationMenuItem } from 'twenty-sdk';
import { EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER } from 'src/views/example-view';
import { EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER } from 'src/views/example-view';
export default defineNavigationMenuItem({
universalIdentifier: '${universalIdentifier}',
@@ -482,7 +489,6 @@ export default defineNavigationMenuItem({
icon: 'IconList',
color: 'blue',
position: 0,
type: 'VIEW',
viewUniversalIdentifier: EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER,
});
`;
@@ -584,14 +590,6 @@ export default defineApplication({
await fs.writeFile(join(appDirectory, fileFolder ?? '', fileName), content);
};
const createYarnLock = async (appDirectory: string) => {
const yarnLockContent = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
`;
await fs.writeFile(join(appDirectory, 'yarn.lock'), yarnLockContent);
};
const createPackageJson = async ({
appName,
appDirectory,
@@ -610,9 +608,8 @@ const createPackageJson = async ({
const devDependencies: Record<string, string> = {
typescript: '^5.9.3',
'@types/node': '^24.7.2',
'@types/react': '^19.0.0',
react: '^19.0.0',
'react-dom': '^19.0.0',
'@types/react': '^18.2.0',
react: '^18.2.0',
oxlint: '^0.16.0',
'twenty-sdk': createTwentyAppPackageJson.version,
};
@@ -1,101 +0,0 @@
import chalk from 'chalk';
import { execSync } from 'node:child_process';
import { platform } from 'node:os';
const DEFAULT_PORT = 2020;
// Minimal health check — the full implementation lives in twenty-sdk
const isServerReady = async (port: number): Promise<boolean> => {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);
try {
const response = await fetch(`http://localhost:${port}/healthz`, {
signal: controller.signal,
});
const body = await response.json();
return body.status === 'ok';
} catch {
return false;
} finally {
clearTimeout(timeoutId);
}
};
export type LocalInstanceResult = {
running: boolean;
serverUrl?: string;
};
export const setupLocalInstance = async (
appDirectory: string,
): Promise<LocalInstanceResult> => {
console.log('');
console.log(chalk.blue('Setting up local Twenty instance...'));
if (await isServerReady(DEFAULT_PORT)) {
const serverUrl = `http://localhost:${DEFAULT_PORT}`;
console.log(chalk.green(`Twenty server detected on ${serverUrl}.`));
return { running: true, serverUrl };
}
// Delegate to `twenty server start` from the scaffolded app
console.log(chalk.gray('Starting local Twenty server...'));
try {
execSync('yarn twenty server start', {
cwd: appDirectory,
stdio: 'inherit',
});
} catch {
console.log(
chalk.yellow(
'Failed to start Twenty server. Run `yarn twenty server start` manually.',
),
);
return { running: false };
}
console.log(chalk.gray('Waiting for Twenty to be ready...'));
const startTime = Date.now();
const timeoutMs = 180 * 1000;
while (Date.now() - startTime < timeoutMs) {
if (await isServerReady(DEFAULT_PORT)) {
const serverUrl = `http://localhost:${DEFAULT_PORT}`;
console.log(chalk.green(`Twenty server is running on ${serverUrl}.`));
console.log(
chalk.gray(
'Workspace ready — login with tim@apple.dev / tim@apple.dev',
),
);
const openCommand = platform() === 'darwin' ? 'open' : 'xdg-open';
try {
execSync(`${openCommand} ${serverUrl}`, { stdio: 'ignore' });
} catch {
// Ignore if browser can't be opened
}
return { running: true, serverUrl };
}
await new Promise((resolve) => setTimeout(resolve, 2000));
}
console.log(
chalk.yellow(
'Twenty server did not become healthy in time. Check: yarn twenty server logs',
),
);
return { running: false };
};
@@ -45,6 +45,7 @@ export default defineConfig({
include: ['src/**/*.integration-test.ts'],
setupFiles: ['src/__tests__/setup-test.ts'],
env: {
TWENTY_API_URL: 'http://localhost:3000',
TWENTY_API_KEY:
'${SEED_API_KEY}',
},
@@ -93,7 +94,7 @@ import * as os from 'os';
import * as path from 'path';
import { beforeAll } from 'vitest';
const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:2020';
const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:3000';
const TEST_CONFIG_DIR = path.join(os.tmpdir(), '.twenty-sdk-test');
const assertServerIsReachable = async () => {
@@ -119,13 +120,12 @@ beforeAll(async () => {
fs.mkdirSync(TEST_CONFIG_DIR, { recursive: true });
const configFile = {
remotes: {
local: {
profiles: {
default: {
apiUrl: process.env.TWENTY_API_URL,
apiKey: process.env.TWENTY_API_KEY,
},
},
defaultRemote: 'local',
};
fs.writeFileSync(
@@ -30,7 +30,7 @@ type AnalysisResult = {
commitments: Commitment[];
};
type RichTextData = {
type RichTextV2Data = {
markdown: string;
blocknote: null;
};
@@ -123,7 +123,7 @@ const createNoteInTwenty = async (
bodyV2: {
markdown: noteBodyMarkdown,
blocknote: null,
} satisfies RichTextData,
} satisfies RichTextV2Data,
};
try {
@@ -159,7 +159,7 @@ const createTaskInTwenty = async (
const taskData: {
title: string;
bodyV2: RichTextData;
bodyV2: RichTextV2Data;
dueAt?: string;
} = {
title: actionItem.title,
@@ -10,4 +10,3 @@
- Creating an object without an index view associated. Unless this is a technical object, user will need to visualize it.
- Creating a view without a navigationMenuItem associated. This will make the view available on the left sidebar.
- Creating a front-end component that has a scroll instead of being responsive to its fixed widget height and width, unless it is specifically meant to be used in a canvas tab.
@@ -5,13 +5,13 @@ This is a [Twenty](https://twenty.com) application project bootstrapped with [`c
First, authenticate to your workspace:
```bash
yarn twenty remote add --local
yarn twenty auth:login
```
Then, start development mode to sync your app and watch for changes:
```bash
yarn twenty dev
yarn twenty app:dev
```
Open your Twenty instance and go to `/settings/applications` section to see the result.
@@ -21,19 +21,19 @@ Open your Twenty instance and go to `/settings/applications` section to see the
Run `yarn twenty help` to list all available commands. Common commands:
```bash
# Remotes & Authentication
yarn twenty remote add --local # Authenticate with Twenty
yarn twenty remote status # Check auth status
yarn twenty remote switch # Switch default remote
yarn twenty remote list # List all configured remotes
yarn twenty remote remove <name> # Remove a remote
# Authentication
yarn twenty auth:login # Authenticate with Twenty
yarn twenty auth:logout # Remove credentials
yarn twenty auth:status # Check auth status
yarn twenty auth:switch # Switch default workspace
yarn twenty auth:list # List all configured workspaces
# Application
yarn twenty dev # Start dev mode (watch, build, sync, and auto-generate typed client)
yarn twenty add # Add a new entity (object, field, function, front-component, role, view, navigation-menu-item)
yarn twenty logs # Stream function logs
yarn twenty exec # Execute a function with JSON payload
yarn twenty uninstall # Uninstall app from workspace
yarn twenty app:dev # Start dev mode (watch, build, sync, and auto-generate typed client)
yarn twenty entity:add # Add a new entity (object, field, function, front-component, role, view, navigation-menu-item)
yarn twenty function:logs # Stream function logs
yarn twenty function:execute # Execute a function with JSON payload
yarn twenty app:uninstall # Uninstall app from workspace
```
## LLMs instructions
@@ -32,7 +32,7 @@ type AnalysisResult = {
commitments: Commitment[];
};
type RichTextData = {
type RichTextV2Data = {
markdown: string;
blocknote: null;
};
@@ -362,7 +362,7 @@ const createNoteInTwenty = async (
bodyV2: {
markdown: noteBodyMarkdown,
blocknote: null,
} satisfies RichTextData,
} satisfies RichTextV2Data,
};
try {
@@ -451,7 +451,7 @@ const createTaskInTwenty = async (
const taskData: {
title: string;
bodyV2: RichTextData;
bodyV2: RichTextV2Data;
dueAt?: string;
assigneeId?: string;
} = {
@@ -9,9 +9,9 @@
},
"packageManager": "yarn@4.9.2",
"scripts": {
"dev": "twenty dev",
"exec": "twenty exec",
"uninstall": "twenty uninstall",
"app:dev": "twenty app:dev",
"function:execute": "twenty function:execute",
"app:uninstall": "twenty app:uninstall",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
},
@@ -9,16 +9,16 @@
},
"packageManager": "yarn@4.9.2",
"scripts": {
"remote:add": "twenty remote add --local",
"remote:status": "twenty remote status",
"remote:switch": "twenty remote switch",
"remote:list": "twenty remote list",
"remote:remove": "twenty remote remove",
"dev": "twenty dev",
"add": "twenty add",
"logs": "twenty logs",
"exec": "twenty exec",
"uninstall": "twenty uninstall",
"auth:login": "twenty auth:login",
"auth:logout": "twenty auth:logout",
"auth:status": "twenty auth:status",
"auth:switch": "twenty auth:switch",
"auth:list": "twenty auth:list",
"app:dev": "twenty app:dev",
"entity:add": "twenty entity:add",
"function:logs": "twenty function:logs",
"function:execute": "twenty function:execute",
"app:uninstall": "twenty app:uninstall",
"help": "twenty help",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
@@ -9,16 +9,16 @@
},
"packageManager": "yarn@4.9.2",
"scripts": {
"remote:add": "twenty remote add --local",
"remote:status": "twenty remote status",
"remote:switch": "twenty remote switch",
"remote:list": "twenty remote list",
"remote:remove": "twenty remote remove",
"dev": "twenty dev",
"add": "twenty add",
"logs": "twenty logs",
"exec": "twenty exec",
"uninstall": "twenty uninstall",
"auth:login": "twenty auth:login",
"auth:logout": "twenty auth:logout",
"auth:status": "twenty auth:status",
"auth:switch": "twenty auth:switch",
"auth:list": "twenty auth:list",
"app:dev": "twenty app:dev",
"entity:add": "twenty entity:add",
"function:logs": "twenty function:logs",
"function:execute": "twenty function:execute",
"app:uninstall": "twenty app:uninstall",
"help": "twenty help",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
@@ -9,16 +9,16 @@
},
"packageManager": "yarn@4.9.2",
"scripts": {
"remote:add": "twenty remote add --local",
"remote:status": "twenty remote status",
"remote:switch": "twenty remote switch",
"remote:list": "twenty remote list",
"remote:remove": "twenty remote remove",
"dev": "twenty dev",
"add": "twenty add",
"logs": "twenty logs",
"exec": "twenty exec",
"uninstall": "twenty uninstall",
"auth:login": "twenty auth:login",
"auth:logout": "twenty auth:logout",
"auth:status": "twenty auth:status",
"auth:switch": "twenty auth:switch",
"auth:list": "twenty auth:list",
"app:dev": "twenty app:dev",
"entity:add": "twenty entity:add",
"function:logs": "twenty function:logs",
"function:execute": "twenty function:execute",
"app:uninstall": "twenty app:uninstall",
"help": "twenty help",
"lint": "oxlint -c .oxlintrc.json .",
"lint:fix": "oxlint --fix -c .oxlintrc.json ."
@@ -1,10 +1,8 @@
import { defineNavigationMenuItem } from 'twenty-sdk';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/post-card-recipient.object';
import { ALL_POST_CARD_RECIPIENTS_VIEW_ID } from '../views/all-post-card-recipients.view';
export default defineNavigationMenuItem({
universalIdentifier: 'c1a2b3c4-0003-4a7b-8c9d-0e1f2a3b4c5d',
position: 2,
type: NavigationMenuItemType.OBJECT,
targetObjectUniversalIdentifier: POST_CARD_RECIPIENT_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: ALL_POST_CARD_RECIPIENTS_VIEW_ID,
});
@@ -1,10 +1,8 @@
import { defineNavigationMenuItem } from 'twenty-sdk';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { POST_CARD_UNIVERSAL_IDENTIFIER } from '../objects/post-card.object';
import { ALL_POST_CARDS_VIEW_ID } from '../views/all-post-cards.view';
export default defineNavigationMenuItem({
universalIdentifier: 'c1a2b3c4-0001-4a7b-8c9d-0e1f2a3b4c5d',
position: 0,
type: NavigationMenuItemType.OBJECT,
targetObjectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: ALL_POST_CARDS_VIEW_ID,
});
@@ -1,10 +1,8 @@
import { defineNavigationMenuItem } from 'twenty-sdk';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { RECIPIENT_UNIVERSAL_IDENTIFIER } from '../objects/recipient.object';
import { ALL_RECIPIENTS_VIEW_ID } from '../views/all-recipients.view';
export default defineNavigationMenuItem({
universalIdentifier: 'c1a2b3c4-0002-4a7b-8c9d-0e1f2a3b4c5d',
position: 1,
type: NavigationMenuItemType.OBJECT,
targetObjectUniversalIdentifier: RECIPIENT_UNIVERSAL_IDENTIFIER,
viewUniversalIdentifier: ALL_RECIPIENTS_VIEW_ID,
});
-1
View File
@@ -10,4 +10,3 @@
- Creating an object without an index view associated. Unless this is a technical object, user will need to visualize it.
- Creating a view without a navigationMenuItem associated. This will make the view available on the left sidebar.
- Creating a front-end component that has a scroll instead of being responsive to its fixed widget height and width, unless it is specifically meant to be used in a canvas tab.
+13 -13
View File
@@ -5,13 +5,13 @@ This is a [Twenty](https://twenty.com) application project bootstrapped with [`c
First, authenticate to your workspace:
```bash
yarn twenty remote add --local
yarn twenty auth:login
```
Then, start development mode to sync your app and watch for changes:
```bash
yarn twenty dev
yarn twenty app:dev
```
Open your Twenty instance and go to `/settings/applications` section to see the result.
@@ -21,19 +21,19 @@ Open your Twenty instance and go to `/settings/applications` section to see the
Run `yarn twenty help` to list all available commands. Common commands:
```bash
# Remotes & Authentication
yarn twenty remote add --local # Authenticate with Twenty
yarn twenty remote status # Check auth status
yarn twenty remote switch # Switch default remote
yarn twenty remote list # List all configured remotes
yarn twenty remote remove <name> # Remove a remote
# Authentication
yarn twenty auth:login # Authenticate with Twenty
yarn twenty auth:logout # Remove credentials
yarn twenty auth:status # Check auth status
yarn twenty auth:switch # Switch default workspace
yarn twenty auth:list # List all configured workspaces
# Application
yarn twenty dev # Start dev mode (watch, build, sync, and auto-generate typed client)
yarn twenty add # Add a new entity (object, field, function, front-component, role, view, navigation-menu-item)
yarn twenty logs # Stream function logs
yarn twenty exec # Execute a function with JSON payload
yarn twenty uninstall # Uninstall app from workspace
yarn twenty app:dev # Start dev mode (watch, build, sync, and auto-generate typed client)
yarn twenty entity:add # Add a new entity (object, field, function, front-component, role, view, navigation-menu-item)
yarn twenty function:logs # Stream function logs
yarn twenty function:execute # Execute a function with JSON payload
yarn twenty app:uninstall # Uninstall app from workspace
```
## Integration Tests
@@ -29,13 +29,12 @@ beforeAll(async () => {
fs.mkdirSync(TEST_CONFIG_DIR, { recursive: true });
const configFile = {
remotes: {
local: {
profiles: {
default: {
apiUrl: process.env.TWENTY_API_URL,
apiKey: process.env.TWENTY_API_KEY,
},
},
defaultRemote: 'local',
};
fs.writeFileSync(
@@ -1,6 +1,5 @@
import { defineNavigationMenuItem } from 'twenty-sdk';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER } from 'src/views/example-view';
import { EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER } from 'src/views/example-view';
export default defineNavigationMenuItem({
universalIdentifier: '10f90627-e9c2-44b7-9742-bed77e3d1b17',
@@ -8,6 +7,5 @@ export default defineNavigationMenuItem({
icon: 'IconList',
color: 'blue',
position: 0,
type: NavigationMenuItemType.VIEW,
viewUniversalIdentifier: EXAMPLE_VIEW_UNIVERSAL_IDENTIFIER,
});
@@ -7,4 +7,3 @@
- Creating an object without an index view associated. Unless this is a technical object, user will need to visualize it.
- Creating a view without a navigationMenuItem associated. This will make the view available on the left sidebar.
- Creating a front-end component that has a scroll instead of being responsive to its fixed widget height and width, unless it is specifically meant to be used in a canvas tab.
@@ -5,13 +5,13 @@ This is a [Twenty](https://twenty.com) application project bootstrapped with [`c
First, authenticate to your workspace:
```bash
yarn twenty remote add --local
yarn twenty auth:login
```
Then, start development mode to sync your app and watch for changes:
```bash
yarn twenty dev
yarn twenty app:dev
```
Open your Twenty instance and go to `/settings/applications` section to see the result.
@@ -21,19 +21,19 @@ Open your Twenty instance and go to `/settings/applications` section to see the
Run `yarn twenty help` to list all available commands. Common commands:
```bash
# Remotes & Authentication
yarn twenty remote add --local # Authenticate with Twenty
yarn twenty remote status # Check auth status
yarn twenty remote switch # Switch default remote
yarn twenty remote list # List all configured remotes
yarn twenty remote remove <name> # Remove a remote
# Authentication
yarn twenty auth:login # Authenticate with Twenty
yarn twenty auth:logout # Remove credentials
yarn twenty auth:status # Check auth status
yarn twenty auth:switch # Switch default workspace
yarn twenty auth:list # List all configured workspaces
# Application
yarn twenty dev # Start dev mode (watch, build, sync, and auto-generate typed client)
yarn twenty add # Add a new entity (object, field, function, front-component, role, view, navigation-menu-item)
yarn twenty logs # Stream function logs
yarn twenty exec # Execute a function with JSON payload
yarn twenty uninstall # Uninstall app from workspace
yarn twenty app:dev # Start dev mode (watch, build, sync, and auto-generate typed client)
yarn twenty entity:add # Add a new entity (object, field, function, front-component, role, view, navigation-menu-item)
yarn twenty function:logs # Stream function logs
yarn twenty function:execute # Execute a function with JSON payload
yarn twenty app:uninstall # Uninstall app from workspace
```
## LLMs instructions
@@ -236,7 +236,7 @@ const handler = async (event: any) => {
},
});
// TODO: remove `as any` after running `yarn twenty dev` to regenerate the typed client
// TODO: remove `as any` after running `yarn twenty app:dev` to regenerate the typed client
const updateSummary = async (markdown: string) => {
await client.mutation({
updateCallRecording: {
@@ -1,12 +1,10 @@
import { CALL_RECORDING_VIEW_UNIVERSAL_IDENTIFIER } from 'src/views/call-recording-view';
import { defineNavigationMenuItem } from 'twenty-sdk';
import { NavigationMenuItemType } from 'twenty-shared/types';
export default defineNavigationMenuItem({
universalIdentifier: '5248a62d-7d2e-43a7-ba45-6e8f61876a71',
name: 'Call recordings',
icon: 'IconPhone',
position: 0,
type: NavigationMenuItemType.VIEW,
viewUniversalIdentifier: CALL_RECORDING_VIEW_UNIVERSAL_IDENTIFIER,
});
@@ -81,7 +81,7 @@ export default defineObject({
},
{
universalIdentifier: TRANSCRIPT_FIELD_UNIVERSAL_IDENTIFIER,
type: FieldType.RICH_TEXT,
type: FieldType.RICH_TEXT_V2,
name: 'transcript',
label: 'Transcript',
description: 'Human-readable transcript of the call',
@@ -114,7 +114,7 @@ export default defineObject({
},
{
universalIdentifier: SUMMARY_FIELD_UNIVERSAL_IDENTIFIER,
type: FieldType.RICH_TEXT,
type: FieldType.RICH_TEXT_V2,
name: 'summary',
label: 'Summary',
description: 'AI-generated summary of the call',
@@ -16,7 +16,7 @@ Use this skill when a user asks you to summarize, analyze, or extract insights f
## How to Access the Data
1. Use \`find_one_callRecording\` to fetch the call recording by its ID.
2. Read the \`transcript\` field (RICH_TEXT, markdown format) which contains the full conversation.
2. Read the \`transcript\` field (RICH_TEXT_V2, markdown format) which contains the full conversation.
3. The transcript uses the format: **Speaker Name:** spoken text
## What to Produce
@@ -1,5 +1,4 @@
import { defineNavigationMenuItem } from 'twenty-sdk';
import { NavigationMenuItemType } from 'twenty-shared/types';
import { UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers.constant';
export default defineNavigationMenuItem({
@@ -7,7 +6,6 @@ export default defineNavigationMenuItem({
name: 'Self host user',
icon: 'IconList',
position: 1,
type: NavigationMenuItemType.VIEW,
viewUniversalIdentifier:
UNIVERSAL_IDENTIFIERS.views.selfHostingUserView.universalIdentifier,
});
@@ -1,42 +0,0 @@
# Development infrastructure services only (Postgres + Redis).
# Use this when developing locally against the source code.
#
# Usage:
# docker compose -f docker-compose.dev.yml up -d
# docker compose -f docker-compose.dev.yml down # stop
# docker compose -f docker-compose.dev.yml down -v # stop + wipe data
name: twenty-dev
services:
db:
image: postgres:16
volumes:
- dev-db-data:/var/lib/postgresql/data
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: default
healthcheck:
test: pg_isready -U postgres -h localhost -d postgres
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
redis:
image: redis:7
ports:
- "6379:6379"
command: ["--maxmemory-policy", "noeviction"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
volumes:
dev-db-data:
@@ -38,6 +38,7 @@ services:
# EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-contact@yourdomain.com}
# EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:-"John from YourDomain"}
# EMAIL_SYSTEM_ADDRESS: ${EMAIL_SYSTEM_ADDRESS:-system@yourdomain.com}
# EMAIL_DRIVER: ${EMAIL_DRIVER:-smtp}
# EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST:-smtp.gmail.com}
# EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT:-465}
@@ -91,6 +92,7 @@ services:
# EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-contact@yourdomain.com}
# EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:-"John from YourDomain"}
# EMAIL_SYSTEM_ADDRESS: ${EMAIL_SYSTEM_ADDRESS:-system@yourdomain.com}
# EMAIL_DRIVER: ${EMAIL_DRIVER:-smtp}
# EMAIL_SMTP_HOST: ${EMAIL_SMTP_HOST:-smtp.gmail.com}
# EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT:-465}
@@ -61,6 +61,7 @@
"EMAIL_SMTP_NO_TLS": { "type": "boolean" },
"EMAIL_FROM_ADDRESS": { "type": "string" },
"EMAIL_FROM_NAME": { "type": "string" },
"EMAIL_SYSTEM_ADDRESS": { "type": "string" },
"IS_EMAIL_VERIFICATION_REQUIRED": { "type": "boolean" },
"EMAIL_VERIFICATION_TOKEN_EXPIRES_IN": { "type": "string" },
"PASSWORD_RESET_TOKEN_EXPIRES_IN": { "type": "string" }
@@ -1,130 +0,0 @@
ARG APP_VERSION
# === Stage 1: Common dependencies ===
FROM node:22-alpine AS common-deps
WORKDIR /app
COPY ./package.json ./yarn.lock ./.yarnrc.yml ./tsconfig.base.json ./nx.json /app/
COPY ./.yarn/releases /app/.yarn/releases
COPY ./.yarn/patches /app/.yarn/patches
COPY ./packages/twenty-emails/package.json /app/packages/twenty-emails/
COPY ./packages/twenty-server/package.json /app/packages/twenty-server/
COPY ./packages/twenty-server/patches /app/packages/twenty-server/patches
COPY ./packages/twenty-ui/package.json /app/packages/twenty-ui/
COPY ./packages/twenty-shared/package.json /app/packages/twenty-shared/
COPY ./packages/twenty-front/package.json /app/packages/twenty-front/
COPY ./packages/twenty-sdk/package.json /app/packages/twenty-sdk/
RUN yarn && yarn cache clean && npx nx reset
# === Stage 2: Build server from source ===
FROM common-deps AS twenty-server-build
COPY ./packages/twenty-emails /app/packages/twenty-emails
COPY ./packages/twenty-shared /app/packages/twenty-shared
COPY ./packages/twenty-ui /app/packages/twenty-ui
COPY ./packages/twenty-sdk /app/packages/twenty-sdk
COPY ./packages/twenty-server /app/packages/twenty-server
RUN npx nx run twenty-server:build
RUN yarn workspaces focus --production twenty-emails twenty-shared twenty-sdk twenty-server
# === Stage 3: Build frontend from source ===
# Requires ~10GB Docker memory. To skip, pre-build on host first:
# npx nx build twenty-front
# The COPY below will pick up packages/twenty-front/build/ if it exists.
FROM common-deps AS twenty-front-build
COPY --from=twenty-server-build /app/package.json /tmp/.build-sentinel
COPY ./packages/twenty-front /app/packages/twenty-front
COPY ./packages/twenty-ui /app/packages/twenty-ui
COPY ./packages/twenty-shared /app/packages/twenty-shared
COPY ./packages/twenty-sdk /app/packages/twenty-sdk
RUN if [ -d /app/packages/twenty-front/build ]; then \
echo "Using pre-built frontend from host"; \
else \
NODE_OPTIONS="--max-old-space-size=8192" npx nx build twenty-front; \
fi
# === Stage 4: s6-overlay ===
FROM alpine:3.20 AS s6-fetch
ARG S6_OVERLAY_VERSION=3.2.0.2
ARG TARGETARCH
RUN if [ "$TARGETARCH" = "arm64" ]; then echo "aarch64" > /tmp/s6arch; \
else echo "x86_64" > /tmp/s6arch; fi
RUN S6_ARCH=$(cat /tmp/s6arch) && \
wget -O /tmp/s6-overlay-noarch.tar.xz \
"https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz" && \
wget -O /tmp/s6-overlay-noarch.tar.xz.sha256 \
"https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz.sha256" && \
wget -O /tmp/s6-overlay-arch.tar.xz \
"https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz" && \
wget -O /tmp/s6-overlay-arch.tar.xz.sha256 \
"https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz.sha256" && \
cd /tmp && \
NOARCH_SUM=$(awk '{print $1}' s6-overlay-noarch.tar.xz.sha256) && \
ARCH_SUM=$(awk '{print $1}' s6-overlay-arch.tar.xz.sha256) && \
echo "$NOARCH_SUM s6-overlay-noarch.tar.xz" | sha256sum -c - && \
echo "$ARCH_SUM s6-overlay-arch.tar.xz" | sha256sum -c -
# === Stage 5: Final all-in-one image ===
FROM node:22-alpine
# s6-overlay
COPY --from=s6-fetch /tmp/s6-overlay-noarch.tar.xz /tmp/
COPY --from=s6-fetch /tmp/s6-overlay-arch.tar.xz /tmp/
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz \
&& tar -C / -Jxpf /tmp/s6-overlay-arch.tar.xz \
&& rm /tmp/s6-overlay-*.tar.xz
# Infrastructure: Postgres, Redis, and utilities
RUN apk add --no-cache \
postgresql16 postgresql16-contrib \
redis \
curl jq su-exec
# tsx for database setup scripts
RUN npm install -g tsx
# Twenty application (both server and frontend built from source)
COPY --from=twenty-server-build /app /app
COPY --from=twenty-front-build /app/packages/twenty-front/build /app/packages/twenty-server/dist/front
# s6 service definitions
COPY packages/twenty-docker/twenty-app-dev/rootfs/ /
# Data directories
RUN mkdir -p /data/postgres /data/redis /app/.local-storage \
&& chown -R postgres:postgres /data/postgres \
&& chown 1000:1000 /data/redis /app/.local-storage
ARG REACT_APP_SERVER_BASE_URL
ARG APP_VERSION=0.0.0
# Tell s6-overlay to preserve container environment variables
ENV S6_KEEP_ENV=1
# Environment defaults
ENV PG_DATABASE_URL=postgres://twenty:twenty@localhost:5432/default \
SERVER_URL=http://localhost:2020 \
REDIS_URL=redis://localhost:6379 \
STORAGE_TYPE=local \
APP_SECRET=twenty-app-dev-secret-not-for-production \
REACT_APP_SERVER_BASE_URL=$REACT_APP_SERVER_BASE_URL \
APP_VERSION=$APP_VERSION \
NODE_ENV=development \
NODE_PORT=3000 \
DISABLE_DB_MIGRATIONS=true \
DISABLE_CRON_JOBS_REGISTRATION=true \
IS_BILLING_ENABLED=false \
SIGN_IN_PREFILLED=true
EXPOSE 3000
VOLUME ["/data/postgres", "/app/.local-storage"]
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty
LABEL org.opencontainers.image.description="All-in-one Twenty image for local development and SDK usage. Includes PostgreSQL, Redis, server, and worker."
ENTRYPOINT ["/init"]
@@ -1 +0,0 @@
/bin/sh /etc/s6-overlay/scripts/init-db.sh
@@ -1,13 +0,0 @@
#!/bin/sh
# Initialize PostgreSQL data directory if empty
if [ ! -f /data/postgres/PG_VERSION ]; then
echo "Initializing PostgreSQL data directory..."
su-exec postgres initdb -D /data/postgres --auth=trust --encoding=UTF8
# Allow local connections without password
echo "host all all 127.0.0.1/32 trust" >> /data/postgres/pg_hba.conf
echo "host all all ::1/128 trust" >> /data/postgres/pg_hba.conf
fi
exec su-exec postgres postgres -D /data/postgres \
-c listen_addresses=localhost \
-c unix_socket_directories=/tmp
@@ -1,6 +0,0 @@
#!/bin/sh
exec redis-server \
--dir /data/redis \
--maxmemory-policy noeviction \
--bind 127.0.0.1 \
--protected-mode yes
@@ -1,3 +0,0 @@
#!/bin/sh
cd /app/packages/twenty-server
exec yarn start:prod
@@ -1,3 +0,0 @@
#!/bin/sh
cd /app/packages/twenty-server
exec yarn worker:prod
@@ -1,56 +0,0 @@
#!/bin/sh
set -e
# Wait for PostgreSQL to be ready (timeout after 60s)
echo "Waiting for PostgreSQL..."
TRIES=0
until su-exec postgres pg_isready -h localhost; do
TRIES=$((TRIES + 1))
if [ "$TRIES" -ge 120 ]; then
echo "ERROR: PostgreSQL did not become ready within 60s"
exit 1
fi
sleep 0.5
done
echo "PostgreSQL is ready."
# Create role if it doesn't exist
su-exec postgres psql -h localhost -tc \
"SELECT 1 FROM pg_roles WHERE rolname='twenty'" | grep -q 1 \
|| su-exec postgres psql -h localhost -c "CREATE ROLE twenty WITH LOGIN PASSWORD 'twenty' SUPERUSER"
# Create database if it doesn't exist
su-exec postgres psql -h localhost -tc \
"SELECT 1 FROM pg_database WHERE datname='default'" | grep -q 1 \
|| su-exec postgres createdb -h localhost -O twenty default
# Run Twenty database setup and migrations
cd /app/packages/twenty-server
has_schema=$(PGPASSWORD=twenty psql -h localhost -U twenty -d default -tAc \
"SELECT EXISTS (SELECT 1 FROM information_schema.schemata WHERE schema_name = 'core')")
if [ "$has_schema" = "f" ]; then
echo "Database appears to be empty, running initial setup..."
NODE_OPTIONS="--max-old-space-size=1500" tsx ./scripts/setup-db.ts
fi
# Always run migrations (idempotent — skips already-applied ones)
yarn database:migrate:prod
yarn command:prod cache:flush
yarn command:prod upgrade
yarn command:prod cache:flush
# Only seed on first boot — check if the dev workspace already exists
has_workspace=$(PGPASSWORD=twenty psql -h localhost -U twenty -d default -tAc \
"SELECT EXISTS (SELECT 1 FROM core.workspace WHERE id = '20202020-1c25-4d02-bf25-6aeccf7ea419')")
if [ "$has_workspace" = "f" ]; then
echo "Seeding app dev data..."
yarn command:prod workspace:seed:dev --light || true
else
echo "Dev workspace already seeded, skipping."
fi
echo "Database initialization complete."
+4 -1
View File
@@ -15,6 +15,7 @@ COPY ./packages/twenty-ui/package.json /app/packages/twenty-ui/
COPY ./packages/twenty-shared/package.json /app/packages/twenty-shared/
COPY ./packages/twenty-front/package.json /app/packages/twenty-front/
COPY ./packages/twenty-sdk/package.json /app/packages/twenty-sdk/
COPY ./packages/twenty-standard-application/package.json /app/packages/twenty-standard-application/
# Install all dependencies
RUN yarn && yarn cache clean && npx nx reset
@@ -28,11 +29,13 @@ COPY ./packages/twenty-emails /app/packages/twenty-emails
COPY ./packages/twenty-shared /app/packages/twenty-shared
COPY ./packages/twenty-ui /app/packages/twenty-ui
COPY ./packages/twenty-sdk /app/packages/twenty-sdk
COPY ./packages/twenty-standard-application /app/packages/twenty-standard-application
COPY ./packages/twenty-server /app/packages/twenty-server
RUN npx nx build twenty-standard-application
RUN npx nx run twenty-server:build
RUN yarn workspaces focus --production twenty-emails twenty-shared twenty-sdk twenty-server
RUN yarn workspaces focus --production twenty-emails twenty-shared twenty-sdk twenty-standard-application twenty-server
# Build the front
FROM common-deps AS twenty-front-build
@@ -9,7 +9,7 @@ The goal here is to have a consistent codebase, which is easy to read and easy t
For this, it's better to be a bit more verbose than to be too concise.
Always keep in mind that people read code more often than they write it, especially on an open source project, where anyone can contribute.
Always keep in mind that people read code more often than they write it, specially on an open source project, where anyone can contribute.
There are a lot of rules that are not defined here, but that are automatically checked by linters.
@@ -150,7 +150,7 @@ type MyType = {
### Use string literals instead of enums
[String literals](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) are the go-to way to handle enum-like values in TypeScript. They are easier to extend with Pick and Omit, and offer a better developer experience, especially with code completion.
[String literals](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) are the go-to way to handle enum-like values in TypeScript. They are easier to extend with Pick and Omit, and offer a better developer experience, specially with code completion.
You can see why TypeScript recommends avoiding enums [here](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#enums).
@@ -288,3 +288,4 @@ An Oxlint rule, `typescript/consistent-type-imports`, enforces the no-type impor
Please note that this rule specifically addresses rare edge cases where unintentional type imports occur. TypeScript itself discourages this practice, as mentioned in the [TypeScript 3.8 release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html). In most situations, you should not need to use type-only imports.
To ensure your code complies with this rule, make sure to run Oxlint as part of your development workflow.
@@ -7,7 +7,7 @@ description: "The guide for contributors (or curious developers) who want to run
## Prerequisites
<Tabs>
<Tab title="Linux and macOS">
<Tab title="Linux and MacOS">
Before you can install and use Twenty, make sure you install the following on your computer:
- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
@@ -31,7 +31,7 @@ wsl --install
```
You should now see a prompt to restart your computer. If not, restart it manually.
Upon restart, a PowerShell window will open and install Ubuntu. This may take up some time.
Upon restart, a powershell window will open and install Ubuntu. This may take up some time.
You'll see a prompt to create a username and password for your Ubuntu installation.
2. Install and configure git
@@ -104,7 +104,7 @@ You should run all commands in the following steps from the root of the project.
<Tabs>
<Tab title="Linux">
**Option 1 (preferred):** To provision your database locally:
Use the following link to install PostgreSQL on your Linux machine: [PostgreSQL Installation](https://www.postgresql.org/download/linux/)
Use the following link to install Postgresql on your Linux machine: [Postgresql Installation](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
@@ -131,7 +131,7 @@ You should run all commands in the following steps from the root of the project.
```
The installer might not create the `postgres` user by default when installing
via Homebrew on macOS. Instead, it creates a PostgreSQL role that matches your macOS
via Homebrew on MacOS. Instead, it creates a PostgreSQL role that matches your macOS
username (e.g., "john").
To check and create the `postgres` user if necessary, follow these steps:
```bash
@@ -174,8 +174,8 @@ You should run all commands in the following steps from the root of the project.
<Tab title="Windows (WSL)">
All the following steps are to be run in the WSL terminal (within your virtual machine)
**Option 1:** To provision your PostgreSQL locally:
Use the following link to install PostgreSQL on your Linux virtual machine: [PostgreSQL Installation](https://www.postgresql.org/download/linux/)
**Option 1:** To provision your Postgresql locally:
Use the following link to install Postgresql on your Linux virtual machine: [Postgresql Installation](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
@@ -190,12 +190,10 @@ You should run all commands in the following steps from the root of the project.
</Tab>
</Tabs>
You can now access the database at `localhost:5432`.
If you used the Docker option above, the default credentials are user `postgres` and password `postgres`. For native PostgreSQL installations, use the credentials and roles configured on your machine.
You can now access the database at [localhost:5432](localhost:5432), with user `postgres` and password `postgres` .
## Step 4: Set up a Redis Database (cache)
Twenty requires a Redis cache to provide the best performance.
Twenty requires a redis cache to provide the best performance
<Tabs>
<Tab title="Linux">
@@ -212,10 +210,8 @@ Twenty requires a Redis cache to provide the best performance.
```bash
brew install redis
```
Start your Redis server:
```bash
brew services start redis
```
Start your redis server:
```brew services start redis```
**Option 2:** If you have docker installed:
```bash
@@ -233,11 +229,11 @@ Twenty requires a Redis cache to provide the best performance.
</Tab>
</Tabs>
If you need a client GUI, we recommend [Redis Insight](https://redis.io/insight/) (free version available).
If you need a Client GUI, we recommend [redis insight](https://redis.io/insight/) (free version available)
## Step 5: Set up environment variables
## Step 5: Setup environment variables
Use environment variables or `.env` files to configure your project. More info [here](/developers/self-host/capabilities/setup).
Use environment variables or `.env` files to configure your project. More info [here](/developers/self-host/capabilities/setup)
Copy the `.env.example` files in `/front` and `/server`:
```bash
@@ -20,51 +20,19 @@ Apps let you build and manage Twenty customizations **as code**. Instead of conf
## Prerequisites
- Node.js 24+ and Yarn 4
- Docker (for the local Twenty dev server)
- A Twenty workspace and an API key (create one at https://app.twenty.com/settings/api-webhooks)
## Getting Started
Create a new app using the official scaffolder. It can automatically start a local Twenty instance for you:
Create a new app using the official scaffolder, then authenticate and start developing:
```bash filename="Terminal"
# Scaffold a new app — the CLI will offer to start a local Twenty server
# Scaffold a new app (includes all examples by default)
npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
# Start dev mode: automatically syncs local changes to your workspace
yarn twenty dev
```
### Local Server Management
The SDK includes commands to manage a local Twenty dev server (all-in-one Docker image with PostgreSQL, Redis, server, and worker):
```bash filename="Terminal"
# Start the local server (pulls the image if needed)
yarn twenty server start
# Check server status
yarn twenty server status
# Stream server logs
yarn twenty server logs
# Stop the server
yarn twenty server stop
# Reset all data and start fresh
yarn twenty server reset
```
The local server comes pre-seeded with a workspace and user (`tim@apple.dev` / `tim@apple.dev`), so you can start developing immediately without any manual setup.
### Authentication
Connect your app to the local server using OAuth:
```bash filename="Terminal"
# Authenticate via OAuth (opens browser)
yarn twenty remote add --local
yarn twenty app:dev
```
The scaffolder supports two modes for controlling which example files are included:
@@ -95,12 +63,6 @@ yarn twenty function:execute --preInstall
# Execute the post-install function
yarn twenty function:execute --postInstall
# Build the app for distribution
yarn twenty app:build
# Publish the app to npm or a Twenty server
yarn twenty app:publish
# Uninstall the application from the current workspace
yarn twenty app:uninstall
@@ -1262,113 +1224,6 @@ Key points:
Explore a minimal, end-to-end example that demonstrates objects, logic functions, front components, and multiple triggers [here](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/hello-world):
## Building your app
Once you've developed your app with `app:dev`, use `app:build` to compile it into a distributable package.
```bash filename="Terminal"
# Build the app (output goes to .twenty/output/)
yarn twenty app:build
# Build and create a tarball (.tgz) for distribution
yarn twenty app:build --tarball
```
The build process:
1. **Parses and validates the manifest** — reads all `defineX()` entities from your source files and validates the manifest structure.
2. **Compiles logic functions and front components** — bundles TypeScript sources into ESM `.mjs` files using esbuild.
3. **Generates checksums** — computes MD5 hashes for each built file, stored in the manifest as `builtHandlerChecksum` / `builtComponentChecksum`.
4. **Generates the typed API client** — introspects the GraphQL schema and generates typed `CoreApiClient` and `MetadataApiClient` clients.
5. **Runs a TypeScript type check** — runs `tsc --noEmit` to catch type errors before publishing.
6. **Rebuilds with the generated client** — performs a second compilation pass so the generated client types are included.
7. **Optionally creates a tarball** — if `--tarball` is passed, runs `npm pack` to create a `.tgz` file ready for distribution.
The build output in `.twenty/output/` contains:
```text
.twenty/output/
├── manifest.json # Manifest with checksums for all built files
├── package.json # Copied from app root
├── yarn.lock # Copied from app root
├── src/
│ ├── logic-functions/ # Compiled .mjs logic function files
│ └── front-components/ # Compiled .mjs front component files
├── public/ # Static assets (if any)
└── my-app-1.0.0.tgz # Only with --tarball flag
```
| Option | Description |
|--------|-------------|
| `[appPath]` | Path to the app directory (defaults to current directory) |
| `--tarball` | Also pack the output into a `.tgz` tarball |
## Publishing your app
Use `app:publish` to distribute your app — either to the npm registry or directly to a Twenty server.
### Publish to npm (default)
```bash filename="Terminal"
# Publish to npm (requires npm login)
yarn twenty app:publish
# Publish with a dist-tag (e.g. beta, next)
yarn twenty app:publish --tag beta
```
This builds the app and runs `npm publish` from the `.twenty/output/` directory. The published package can then be installed from the Twenty marketplace by any workspace.
### Publish to a Twenty server
```bash filename="Terminal"
# Publish directly to a Twenty server
yarn twenty app:publish --server https://app.twenty.com
```
This builds the app with a tarball, uploads it to the server via the `uploadAppTarball` GraphQL mutation, and triggers installation in one step. This is useful for private deployments or testing against a specific server.
| Option | Description |
|--------|-------------|
| `[appPath]` | Path to the app directory (defaults to current directory) |
| `--server <url>` | Publish to a Twenty server instead of npm |
| `--token <token>` | Authentication token for the target server |
| `--tag <tag>` | npm dist-tag (e.g. `beta`, `next`) — only for npm publish |
## Application registration
Before an app can be installed in a workspace, it must be **registered**. A registration is a metadata record that describes where the app comes from and how to authenticate it. This is handled automatically by the CLI in most cases.
### Source types
Each registration has a **source type** that determines how the app's files are resolved during installation:
| Source type | How files are resolved | Typical use case |
|-------------|----------------------|------------------|
| `LOCAL` | Files are synced in real-time by the CLI watcher — installation is skipped | Development with `app:dev` |
| `NPM` | Fetched from the npm registry via the `sourcePackage` field | Published apps on npm |
| `TARBALL` | Extracted from an uploaded `.tgz` file stored on the server | Private apps published with `--server` |
### How registration happens
- **`app:dev`** — automatically creates a `LOCAL` registration the first time you run dev mode against a workspace.
- **`app:publish --server`** — uploads a tarball and creates (or updates) a `TARBALL` registration, then installs the app.
- **npm marketplace** — `NPM` registrations are created when apps are synced from the npm registry into the Twenty marketplace catalog.
- **GraphQL API** — you can also create registrations programmatically via the `createApplicationRegistration` mutation.
### Registration vs installation
**Registration** and **installation** are separate concepts:
- A **registration** (`ApplicationRegistration`) is a global metadata record describing the app: its name, source type, OAuth credentials, and marketplace listing status. It exists independently of any workspace.
- An **installation** (`Application`) is a per-workspace instance. When a user installs an app, Twenty resolves the package from the registration's source, writes the built files to storage, and synchronizes the manifest (creating objects, fields, logic functions, etc.) in that workspace.
One registration can be installed in many workspaces. Each workspace gets its own copy of the app's files and data model.
### OAuth credentials
Each registration includes OAuth credentials (`oAuthClientId` and `oAuthClientSecret`) generated at creation time. These are used by the app to authenticate API requests on behalf of users. The client secret is returned **once** at creation — store it securely. You can rotate it later via the `rotateApplicationRegistrationClientSecret` mutation.
## Manual setup (without the scaffolder)
While we recommend using `create-twenty-app` for the best getting-started experience, you can also set up a project manually. Do not install the CLI globally. Instead, add `twenty-sdk` as a local dependency and wire a single script in your package.json:
@@ -4,7 +4,7 @@ title: 1-Click w/ Docker Compose
<Warning>
Docker containers are for production hosting or self-hosting. For contributing, please check the [Local Setup](/developers/contribute/capabilities/local-setup).
Docker containers are for production hosting or self-hosting, for the contribution please check the [Local Setup](/developers/contribute/capabilities/local-setup).
</Warning>
## Overview
@@ -13,7 +13,7 @@ This guide provides step-by-step instructions to install and configure the Twent
**Important:** Only modify settings explicitly mentioned in this guide. Altering other configurations may lead to issues.
See [Setup Environment Variables](/developers/self-host/capabilities/setup) for advanced configuration. All environment variables must be declared in the `docker-compose.yml` file at the server and/or worker level, depending on the variable.
See docs [Setup Environment Variables](/developers/self-host/capabilities/setup) for advanced configuration. All environment variables must be declared in the docker-compose.yml file at the server and / or worker level depending on the variable.
## System Requirements
@@ -237,3 +237,4 @@ docker compose up -d
If you encounter any problem, check [Troubleshooting](/developers/self-host/capabilities/troubleshooting) for solutions.
@@ -289,57 +289,43 @@ yarn command:prod cron:workflow:automated-cron-trigger
**Environment-only mode:** If you set `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false`, add these variables to your `.env` file instead.
</Warning>
## Logic Functions & Code Interpreter
## Logic Functions
Twenty supports logic functions for workflows and the code interpreter for AI data analysis. Both run user-provided code and require explicit configuration for security.
### Security Defaults
**In production (NODE_ENV=production):** Both logic functions and code interpreter default to **Disabled**. You must explicitly enable them with `LOGIC_FUNCTION_TYPE` and `CODE_INTERPRETER_TYPE` if you need these features.
**In development (NODE_ENV=development):** Both default to **LOCAL** for convenience when running locally.
Twenty supports logic functions for workflows and custom logic. The execution environment is configured via the `SERVERLESS_TYPE` environment variable.
<Warning>
**Security Notice:** The local driver (`LOGIC_FUNCTION_TYPE=LOCAL` or `CODE_INTERPRETER_TYPE=LOCAL`) runs code directly on the host in a Node.js process with no sandboxing. It should only be used for trusted code in development. For production deployments handling untrusted code, use `LOGIC_FUNCTION_TYPE=LAMBDA` or `CODE_INTERPRETER_TYPE=E2B` (with sandboxing), or keep them disabled.
**Security Notice:** The local driver (`SERVERLESS_TYPE=LOCAL`) runs code directly on the host in a Node.js process with no sandboxing. It should only be used for trusted code in development. For production deployments handling untrusted code, we highly recommend using `SERVERLESS_TYPE=LAMBDA` or `SERVERLESS_TYPE=DISABLED`.
</Warning>
### Logic Functions - Available Drivers
### Available Drivers
| Driver | Environment Variable | Use Case | Security Level |
|--------|---------------------|----------|----------------|
| Disabled | `LOGIC_FUNCTION_TYPE=DISABLED` | Disable logic functions entirely | N/A |
| Local | `LOGIC_FUNCTION_TYPE=LOCAL` | Development and trusted environments | Low (no sandboxing) |
| Lambda | `LOGIC_FUNCTION_TYPE=LAMBDA` | Production with untrusted code | High (hardware-level isolation) |
| Disabled | `SERVERLESS_TYPE=DISABLED` | Disable logic functions entirely | N/A |
| Local | `SERVERLESS_TYPE=LOCAL` | Development and trusted environments | Low (no sandboxing) |
| Lambda | `SERVERLESS_TYPE=LAMBDA` | Production with untrusted code | High (hardware-level isolation) |
### Logic Functions - Recommended Configuration
### Recommended Configuration
**For development:**
```bash
LOGIC_FUNCTION_TYPE=LOCAL # default when NODE_ENV=development
SERVERLESS_TYPE=LOCAL # default
```
**For production (AWS):**
```bash
LOGIC_FUNCTION_TYPE=LAMBDA
LOGIC_FUNCTION_LAMBDA_REGION=us-east-1
LOGIC_FUNCTION_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID=your-access-key
LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
SERVERLESS_TYPE=LAMBDA
SERVERLESS_LAMBDA_REGION=us-east-1
SERVERLESS_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
SERVERLESS_LAMBDA_ACCESS_KEY_ID=your-access-key
SERVERLESS_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
```
**To disable logic functions:**
```bash
LOGIC_FUNCTION_TYPE=DISABLED # default when NODE_ENV=production
SERVERLESS_TYPE=DISABLED
```
### Code Interpreter - Available Drivers
| Driver | Environment Variable | Use Case | Security Level |
|--------|---------------------|----------|----------------|
| Disabled | `CODE_INTERPRETER_TYPE=DISABLED` | Disable AI code execution | N/A |
| Local | `CODE_INTERPRETER_TYPE=LOCAL` | Development only | Low (no sandboxing) |
| E2B | `CODE_INTERPRETER_TYPE=E_2_B` | Production with sandboxed execution | High (isolated sandbox) |
<Note>
When using `LOGIC_FUNCTION_TYPE=DISABLED` or `CODE_INTERPRETER_TYPE=DISABLED`, any attempt to execute will return an error. This is useful if you want to run Twenty without these capabilities.
When using `SERVERLESS_TYPE=DISABLED`, any attempt to execute a logic function will return an error. This is useful if you want to run Twenty without logic function capabilities.
</Note>
-4
View File
@@ -6302,10 +6302,6 @@
"source": "/developers/extend/capabilities/apps",
"destination": "/developers/extend/apps/getting-started"
},
{
"source": "/developers/extend/mcp",
"destination": "/user-guide/ai/capabilities/mcp"
},
{
"source": "/developers/local-setup",
"destination": "/developers/contribute/capabilities/local-setup"
@@ -8,7 +8,7 @@ title: دليل الأسلوب
لهذا، من الأفضل أن تكون تفصيلًا أكثر قليلاً بدلاً من أن تكون موجزًا للغاية.
دائمًا ضع في اعتبارك أن الناس يقرؤون التعليمات البرمجية أكثر مما يكتبونها، وخاصة في مشروع مفتوح المصدر، حيث يمكن لأي شخص المساهمة.
دائمًا ضع في اعتبارك أن الناس يقرؤون التعليمات البرمجية أكثر مما يكتبونها، وخاصة في المشاريع مفتوحة المصدر، حيث يمكن لأي شخص المساهمة.
هناك العديد من القواعد التي لم يتم تعريفها هنا، ولكن يتم التحقق منها تلقائيًا بواسطة أدوات الفحص.
@@ -6,7 +6,7 @@ description: الدليل للمساهمين (أو المطورين الفضول
## المتطلبات الأساسية
<Tabs>
<Tab title="Linux و macOS">
<Tab title="Linux و MacOS">
قبل أن تتمكن من تثبيت واستخدام Twenty، تأكد من تثبيت الأمور التالية على جهاز الكمبيوتر الخاص بك:
* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
@@ -103,7 +103,7 @@ cd twenty
<Tabs>
<Tab title="Linux">
**الخيار 1 (المفضل):** لتوفير قاعدة بياناتك محليًا:
استخدم الرابط التالي لتثبيت PostgreSQL على جهاز Linux الخاص بك: [تثبيت PostgreSQL](https://www.postgresql.org/download/linux/)
استخدم الرابط التالي لتثبيت Postgresql على جهاز Linux الخاص بك: [تثبيت Postgresql](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
@@ -129,8 +129,8 @@ cd twenty
brew services list
```
قد لا يقوم المُثبِّت بإنشاء المستخدم `postgres` افتراضيًا عند التثبيت
عبر Homebrew على macOS. بدلاً من ذلك، فإنه ينشئ دور PostgreSQL يطابق
المثبت قد لا ينشئ المستخدم `postgres` افتراضيًا عند التثبيت
عبر Homebrew على MacOS. بدلاً من ذلك، فإنه ينشئ دور PostgreSQL يطابق
اسم المستخدم الخاص بك في MacOS (مثل "john").
للتحقق وإنشاء المستخدم `postgres` إذا لزم الأمر، اتبع هذه الخطوات:
```bash
@@ -173,8 +173,8 @@ cd twenty
<Tab title="ويندوز (WSL)">
يجب أن تُنفذ جميع الخطوات التالية في تيرمينال WSL (داخل جهازك الافتراضي)
**الخيار 1:** لتوفير قاعدة بيانات PostgreSQL الخاصة بك محليًا:
استخدم الرابط التالي لتثبيت PostgreSQL على جهاز Linux الافتراضي الخاص بك: [تثبيت PostgreSQL](https://www.postgresql.org/download/linux/)
**الخيار 1:** لتوفير قاعدة بيانات Postgresql الخاصة بك محليًا:
استخدم الرابط التالي لتثبيت Postgresql على جهاز Linux الافتراضي الخاص بك: [تثبيت Postgresql](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
@@ -189,13 +189,11 @@ cd twenty
</Tab>
</Tabs>
يمكنك الآن الوصول إلى قاعدة البيانات على `localhost:5432`.
إذا استخدمت خيار Docker أعلاه، فإن بيانات الاعتماد الافتراضية هي اسم المستخدم `postgres` وكلمة المرور `postgres`. بالنسبة لتثبيتات PostgreSQL الأصلية، استخدم بيانات الاعتماد والأدوار المُكوَّنة على جهازك.
يمكنك الآن الوصول إلى قاعدة البيانات على [localhost:5432](localhost:5432)، مع المستخدم `postgres` وكلمة المرور `postgres`.
## الخطوة 4: إعداد قاعدة بيانات Redis (للتخزين المؤقت)
يتطلب Twenty مخزن بيانات Redis لتقديم أفضل أداء.
يتطلب Twenty مخزن بيانات Redis لتقديم أفضل أداء
<Tabs>
<Tab title="Linux">
@@ -212,10 +210,8 @@ cd twenty
```bash
brew install redis
```
ابدأ تشغيل خادم Redis:
```bash
brew services start redis
```
ابدأ خادم redis الخاص بك:
`brew services start redis`
**الخيار 2:** إذا كنت قد قمت بتثبيت docker:
```bash
@@ -233,11 +229,11 @@ cd twenty
</Tab>
</Tabs>
إذا كنت بحاجة إلى واجهة رسومية للعميل، نوصي بـ [Redis Insight](https://redis.io/insight/) (يتوفر إصدار مجاني).
إذا كنت بحاجة إلى واجهة رسومية للعميل، نوصي بـ [redis insight](https://redis.io/insight/) (يتوفر إصدار مجاني)
## الخطوة 5: إعداد متغيرات البيئة
استخدم متغيرات البيئة أو ملفات `.env` لتكوين مشروعك. المزيد من المعلومات [هنا](/l/ar/developers/self-host/capabilities/setup).
استخدم متغيرات البيئة أو ملفات `.env` لتكوين مشروعك. المزيد من المعلومات [هنا](/l/ar/developers/self-host/capabilities/setup)
انسخ ملفات `.env.example` الموجودة في `/front` و`/server`:
@@ -21,51 +21,19 @@ description: أنشئ وأدِر تخصيصات Twenty على هيئة كود.
## المتطلبات الأساسية
* Node.js 24+ وYarn 4
* Docker (لخادم تطوير Twenty المحلي)
* مساحة عمل Twenty ومفتاح واجهة برمجة التطبيقات (أنشئ واحدًا على https://app.twenty.com/settings/api-webhooks)
## البدء
أنشئ تطبيقًا جديدًا باستخدام المولّد الرسمي. يمكنه بدء مثيل محلي من Twenty تلقائيًا لك:
أنشئ تطبيقًا جديدًا باستخدام المُهيئ الرسمي، ثم قم بالمصادقة وابدأ التطوير:
```bash filename="Terminal"
# إنشاء تطبيق جديد — ستعرض واجهة سطر الأوامر خيار بدء خادم Twenty محلي
# إنشاء تطبيق جديد (يتضمن جميع الأمثلة افتراضيًا)
npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
# ابدأ وضع التطوير: يُزامن التغييرات المحلية تلقائيًا مع مساحة العمل الخاصة بك
yarn twenty dev
```
### إدارة الخادم المحلي
يتضمن SDK أوامر لإدارة خادم تطوير Twenty محلي (صورة Docker متكاملة تتضمن PostgreSQL وRedis والخادم والعامل):
```bash filename="Terminal"
# ابدأ الخادم المحلي (يسحب الصورة إذا لزم الأمر)
yarn twenty server start
# تحقّق من حالة الخادم
yarn twenty server status
# بثّ سجلات الخادم
yarn twenty server logs
# أوقف الخادم
yarn twenty server stop
# أعد ضبط جميع البيانات وابدأ من جديد
yarn twenty server reset
```
يأتي الخادم المحلي مهيأً مسبقًا بمساحة عمل ومستخدم (`tim@apple.dev` / `tim@apple.dev`)، بحيث يمكنك البدء في التطوير فورًا دون أي إعداد يدوي.
### المصادقة
وصّل تطبيقك بالخادم المحلي باستخدام OAuth:
```bash filename="Terminal"
# المصادقة عبر OAuth (يفتح المتصفح)
yarn twenty remote add --local
yarn twenty app:dev
```
يدعم المُنشئ وضعين للتحكم في ملفات الأمثلة التي سيتم تضمينها:
@@ -96,12 +64,6 @@ yarn twenty function:execute --preInstall
# نفّذ دالة ما بعد التثبيت
yarn twenty function:execute --postInstall
# ابنِ التطبيق للتوزيع
yarn twenty app:build
# انشر التطبيق إلى npm أو إلى خادم Twenty
yarn twenty app:publish
# أزل تثبيت التطبيق من مساحة العمل الحالية
yarn twenty app:uninstall
@@ -1278,113 +1240,6 @@ uploadFile(
استكشف مثالًا بسيطًا شاملًا من البداية إلى النهاية يوضح الكائنات والوظائف المنطقية والمكوّنات الأمامية ومشغّلات متعددة [هنا](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/hello-world):
## بناء تطبيقك
بمجرد أن تطوّر تطبيقك باستخدام `app:dev`، استخدم `app:build` لإنشاء حزمة قابلة للتوزيع منه.
```bash filename="Terminal"
# ابنِ التطبيق (الإخراج يذهب إلى .twenty/output/)
yarn twenty app:build
# ابنِ وأنشئ ملف tarball (.tgz) للتوزيع
yarn twenty app:build --tarball
```
عملية البناء:
1. **يقوم بتحليل ملف البيان والتحقق من صحته** — يقرأ جميع الكيانات `defineX()` من ملفات المصدر لديك ويُتحقّق من بنية ملف البيان.
2. **يُصرِّف دوال المنطق ومكوّنات الواجهة** — يُجمّع مصادر TypeScript إلى ملفات ESM `.mjs` باستخدام esbuild.
3. **يولّد قيم التحقّق** — يحسب تجزئات MD5 لكل ملف مُبنًى، وتُخزَّن في ملف البيان كـ `builtHandlerChecksum` / `builtComponentChecksum`.
4. **ينشئ عميل API مضبوط الأنواع** — يفحص مخطط GraphQL ويُنشئ عميلَي `CoreApiClient` و`MetadataApiClient` مضبوطي الأنواع.
5. **يشغّل فحص الأنواع لـ TypeScript** — يشغّل `tsc --noEmit` لاكتشاف أخطاء الأنواع قبل النشر.
6. **يعيد البناء باستخدام العميل المُولَّد** — يُجري مرحلة ترجمة ثانية بحيث تُدرَج أنواع العميل المُولَّد.
7. **ينشئ أرشيف tar اختياريًا** — إذا تم تمرير `--tarball`، يشغّل `npm pack` لإنشاء ملف `.tgz` جاهز للتوزيع.
مخرجات البناء في `.twenty/output/` تتضمّن:
```text
.twenty/output/
├── manifest.json # Manifest with checksums for all built files
├── package.json # Copied from app root
├── yarn.lock # Copied from app root
├── src/
│ ├── logic-functions/ # Compiled .mjs logic function files
│ └── front-components/ # Compiled .mjs front component files
├── public/ # Static assets (if any)
└── my-app-1.0.0.tgz # Only with --tarball flag
```
| الخيار | الوصف |
| ----------- | -------------------------------------------------- |
| `[appPath]` | المسار إلى دليل التطبيق (افتراضيًا: الدليل الحالي) |
| `--tarball` | قم أيضًا بحزم المخرجات في أرشيف `.tgz` |
## نشر تطبيقك
استخدم `app:publish` لتوزيع تطبيقك — إما إلى سجل npm أو مباشرةً إلى خادم Twenty.
### النشر إلى npm (الإعداد الافتراضي)
```bash filename="Terminal"
# Publish to npm (requires npm login)
yarn twenty app:publish
# Publish with a dist-tag (e.g. beta, next)
yarn twenty app:publish --tag beta
```
يقوم هذا ببناء التطبيق وتشغيل `npm publish` من دليل `.twenty/output/`. بعد ذلك يمكن تثبيت الحزمة المنشورة من سوق Twenty بواسطة أي مساحة عمل.
### النشر إلى خادم Twenty
```bash filename="Terminal"
# Publish directly to a Twenty server
yarn twenty app:publish --server https://app.twenty.com
```
يقوم هذا ببناء التطبيق مع أرشيف tar، ويرفعه إلى الخادم عبر العملية `uploadAppTarball` في GraphQL، ويبدأ التثبيت في خطوة واحدة. يكون هذا مفيدًا لعمليات النشر الخاصة أو للاختبار مقابل خادم محدّد.
| الخيار | الوصف |
| ----------------- | -------------------------------------------------------- |
| `[appPath]` | المسار إلى دليل التطبيق (افتراضيًا: الدليل الحالي) |
| `--server <url>` | انشر إلى خادم Twenty بدلًا من npm |
| `--token <token>` | رمز المصادقة للخادم المستهدف |
| `--tag <tag>` | علامة توزيع npm (مثل `beta`، `next`) — للنشر عبر npm فقط |
## تسجيل التطبيق
قبل أن يمكن تثبيت تطبيق في مساحة عمل، يجب أن يكون **مسجّلًا**. التسجيل هو سجل بيانات وصفية يوضّح مصدر التطبيق وكيفية مصادقته. يُعالَج هذا تلقائيًا بواسطة CLI في معظم الحالات.
### أنواع المصادر
لكل تسجيل **نوع مصدر** يحدّد كيفية تحديد ملفات التطبيق أثناء التثبيت:
| نوع المصدر | كيفية تحديد الملفات | حالة الاستخدام النموذجية |
| ---------- | ------------------------------------------------------------------------- | --------------------------------------- |
| `LOCAL` | تتم مزامنة الملفات في الوقت الفعلي بواسطة مُراقِب CLI — يتم تخطّي التثبيت | التطوير باستخدام `app:dev` |
| `NPM` | تُجلب من سجل npm عبر الحقل `sourcePackage` | تطبيقات منشورة على npm |
| `TARBALL` | تُستخرَج من ملف `.tgz` مرفوع ومخزَّن على الخادم | تطبيقات خاصة منشورة باستخدام `--server` |
### كيفية إجراء التسجيل
* **`app:dev`** — ينشئ تلقائيًا تسجيلًا من نوع `LOCAL` في المرة الأولى التي تشغّل فيها وضع التطوير لمساحة عمل.
* **`app:publish --server`** — يرفع أرشيف tar وينشئ (أو يحدّث) تسجيلًا من نوع `TARBALL`، ثم يثبّت التطبيق.
* **سوق npm** — يتم إنشاء تسجيلات `NPM` عند مزامنة التطبيقات من سجل npm إلى كتالوج سوق Twenty.
* **واجهة برمجة تطبيقات GraphQL** — يمكنك أيضًا إنشاء التسجيلات برمجيًا عبر العملية `createApplicationRegistration`.
### التسجيل مقابل التثبيت
**التسجيل** و**التثبيت** مفهومان منفصلان:
* **التسجيل** (`ApplicationRegistration`) هو سجل بيانات وصفية عام يصف التطبيق: اسمه، نوع المصدر، بيانات اعتماد OAuth، وحالة إدراجه في السوق. وهو موجود بشكل مستقل عن أي مساحة عمل.
* **التثبيت** (`Application`) هو مثيل لكل مساحة عمل. عند قيام مستخدم بتثبيت تطبيق، تقوم Twenty بحلّ الحزمة من مصدر التسجيل، وتكتب الملفات المُبنَاة إلى التخزين، وتزامن البيان التعريفي (إنشاء الكائنات والحقول ودوال المنطق، إلخ) في مساحة العمل تلك.
يمكن تثبيت تسجيل واحد في العديد من مساحات العمل. تحصل كل مساحة عمل على نسختها الخاصة من ملفات التطبيق ونموذج البيانات.
### بيانات اعتماد OAuth
يتضمن كل تسجيل بيانات اعتماد OAuth (`oAuthClientId` و`oAuthClientSecret`) يتم إنشاؤها وقت الإنشاء. يستخدمها التطبيق لمصادقة طلبات واجهة برمجة التطبيقات بالنيابة عن المستخدمين. يُعرَض سر العميل مرةً **واحدة** عند الإنشاء — خزّنه بأمان. يمكنك تدويره لاحقًا عبر العملية `rotateApplicationRegistrationClientSecret`.
## إعداد يدوي (بدون المهيئ)
بينما نوصي باستخدام `create-twenty-app` للحصول على أفضل تجربة للبدء، يمكنك أيضًا إعداد مشروع يدويًا. لا تثبّت CLI عالميًا. بدل ذلك، أضف `twenty-sdk` كاعتماد محلي واربط سكربتًا واحدًا في ملف package.json لديك:
@@ -3,7 +3,7 @@ title: بنقرة واحدة مع Docker Compose
---
<Warning>
حاويات Docker مخصصة للاستضافة في بيئة الإنتاج أو للاستضافة الذاتية. للمساهمة، يُرجى الاطلاع على [الإعداد المحلي](/l/ar/developers/contribute/capabilities/local-setup).
الحاويات الخاصة بدوكر مخصصة للاستضافة الإنتاجية أو الاستضافة الذاتية، للتحقيق يرجى التحقق من [الإعداد المحلي](/l/ar/developers/contribute/capabilities/local-setup).
</Warning>
## نظرة عامة
@@ -12,7 +12,7 @@ title: بنقرة واحدة مع Docker Compose
**مهم:** عدّل الإعدادات المذكورة صراحة في هذا الدليل فقط. قد يؤدي تعديل التكوينات الأخرى إلى مشاكل.
راجع [إعداد متغيرات البيئة](/l/ar/developers/self-host/capabilities/setup) لإعداد متقدم. يجب إعلان جميع متغيرات البيئة في ملف `docker-compose.yml` على مستوى الخادم و/أو العامل، اعتمادًا على المتغير.
راجع المستندات الخاصة بـ [إعداد متغيرات البيئة](/l/ar/developers/self-host/capabilities/setup) لإعداد متقدم. يجب إعلان جميع متغيرات البيئة في الملف docker-compose.yml على مستوى الخادم و/أو العامل بناءً على المتغير.
## متطلبات النظام
@@ -297,60 +297,46 @@ yarn command:prod cron:workflow:automated-cron-trigger
**وضع بيئي فقط:** إذا كنت قد ضبطت `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false`، فأضف هذه المتغيرات إلى ملف `.env` الخاص بك بدلاً من ذلك.
</Warning>
## الوظائف المنطقية ومفسر الشيفرة
## الوظائف المنطقية
تدعم Twenty الوظائف المنطقية لعمليات سير العمل ومفسر الشيفرة لتحليل بيانات الذكاء الاصطناعي. كلاهما يقوم بتشغيل الشيفرة المقدمة من المستخدم ويتطلب تهيئة صريحة لأغراض الأمان.
### الإعدادات الافتراضية للأمان
**في بيئة الإنتاج (NODE_ENV=production):** يكون الإعداد الافتراضي لكل من الوظائف المنطقية ومفسر الشيفرة هو **معطل**. يجب تمكينهما صراحة باستخدام `LOGIC_FUNCTION_TYPE` و`CODE_INTERPRETER_TYPE` إذا كنت تحتاج إلى هذه الميزات.
**في بيئة التطوير (NODE_ENV=development):** يكون الإعداد الافتراضي لكليهما **LOCAL** لتسهيل التشغيل محلياً.
تدعم Twenty الوظائف المنطقية لعمليات سير العمل والمنطق المخصص. يتم تكوين بيئة التنفيذ عبر متغير البيئة `SERVERLESS_TYPE`.
<Warning>
**ملاحظة أمنية:** يقوم برنامج التشغيل المحلي (`LOGIC_FUNCTION_TYPE=LOCAL` أو `CODE_INTERPRETER_TYPE=LOCAL`) بتشغيل الشيفرة مباشرة على المضيف ضمن عملية Node.js من دون عزل. يجب استخدامه فقط للشيفرة الموثوقة أثناء التطوير. لعمليات النشر الإنتاجية التي تتعامل مع شيفرة غير موثوقة، استخدم `LOGIC_FUNCTION_TYPE=LAMBDA` أو `CODE_INTERPRETER_TYPE=E2B` (مع وضع الحماية)، أو اتركهما مُعطَّلَيْن.
**ملاحظة أمنية:** يقوم برنامج التشغيل المحلي (`SERVERLESS_TYPE=LOCAL`) بتشغيل الشيفرة مباشرةً على المضيف ضمن عملية Node.js من دون عزل. يجب استخدامه فقط للشيفرة الموثوقة أثناء التطوير. بالنسبة لعمليات النشر الإنتاجية التي تتعامل مع شيفرة غير موثوق بها، نوصي بشدة باستخدام `SERVERLESS_TYPE=LAMBDA` أو `SERVERLESS_TYPE=DISABLED`.
</Warning>
### الوظائف المنطقية - برامج التشغيل المتاحة
### برامج التشغيل المتاحة
| برنامج التشغيل | متغير البيئة | حالة الاستخدام | مستوى الأمان |
| -------------- | ------------------------------ | ------------------------------- | ----------------------------- |
| معطل | `LOGIC_FUNCTION_TYPE=DISABLED` | تعطيل الوظائف المنطقية بالكامل | غير متاح |
| محلي | `LOGIC_FUNCTION_TYPE=LOCAL` | بيئات التطوير والبيئات الموثوقة | منخفض (من دون عزل) |
| Lambda | `LOGIC_FUNCTION_TYPE=LAMBDA` | الإنتاج مع شيفرة غير موثوق بها | مرتفع (عزل على مستوى الأجهزة) |
| برنامج التشغيل | متغير البيئة | حالة الاستخدام | مستوى الأمان |
| -------------- | -------------------------- | ------------------------------- | ----------------------------- |
| معطل | `SERVERLESS_TYPE=DISABLED` | تعطيل الوظائف المنطقية بالكامل | غير متاح |
| محلي | `SERVERLESS_TYPE=LOCAL` | بيئات التطوير والبيئات الموثوقة | منخفض (من دون عزل) |
| Lambda | `SERVERLESS_TYPE=LAMBDA` | الإنتاج مع شيفرة غير موثوق بها | مرتفع (عزل على مستوى الأجهزة) |
### الوظائف المنطقية - الإعداد الموصى به
### التكوين الموصى به
**للتطوير:**
```bash
LOGIC_FUNCTION_TYPE=LOCAL # default when NODE_ENV=development
SERVERLESS_TYPE=LOCAL # default
```
**للإنتاج (AWS):**
```bash
LOGIC_FUNCTION_TYPE=LAMBDA
LOGIC_FUNCTION_LAMBDA_REGION=us-east-1
LOGIC_FUNCTION_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID=your-access-key
LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
SERVERLESS_TYPE=LAMBDA
SERVERLESS_LAMBDA_REGION=us-east-1
SERVERLESS_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
SERVERLESS_LAMBDA_ACCESS_KEY_ID=your-access-key
SERVERLESS_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
```
**لتعطيل الوظائف المنطقية:**
```bash
LOGIC_FUNCTION_TYPE=DISABLED # default when NODE_ENV=production
SERVERLESS_TYPE=DISABLED
```
### مفسر الشيفرة - برامج التشغيل المتاحة
| برنامج التشغيل | متغير البيئة | حالة الاستخدام | مستوى الأمان |
| -------------- | -------------------------------- | ------------------------------------- | ------------------------ |
| معطل | `CODE_INTERPRETER_TYPE=DISABLED` | تعطيل تنفيذ الشيفرة بالذكاء الاصطناعي | غير متاح |
| محلي | `CODE_INTERPRETER_TYPE=LOCAL` | للتطوير فقط | منخفض (من دون عزل) |
| E2B | `CODE_INTERPRETER_TYPE=E_2_B` | الإنتاج مع تنفيذ ضمن صندوق رمل معزول | مرتفعة (صندوق رمل معزول) |
<Note>
عند استخدام `LOGIC_FUNCTION_TYPE=DISABLED` أو `CODE_INTERPRETER_TYPE=DISABLED`، سترجع أي محاولة للتنفيذ خطأً. يكون هذا مفيدًا إذا كنت ترغب في تشغيل Twenty من دون هذه الإمكانات.
عند استخدام `SERVERLESS_TYPE=DISABLED`، ستؤدي أي محاولة لتنفيذ وظيفة منطقية إلى إرجاع خطأ. يكون هذا مفيدًا إذا كنت ترغب في تشغيل Twenty من دون إمكانات الوظائف المنطقية.
</Note>
@@ -1,142 +0,0 @@
---
title: خادم MCP
description: اربط مساعدي الذكاء الاصطناعي بمساحة عمل Twenty الخاصة بك باستخدام بروتوكول سياق النموذج.
---
<Warning>
MCP حاليًا في مرحلة **ألفا** وهو متاح فقط في بعض مساحات العمل. قد لا يكون مفعّلًا لمساحة عملك بعد.
</Warning>
تعرض Twenty خادم [MCP](https://modelcontextprotocol.io/) بحيث تتمكّن مساعدات الذكاء الاصطناعي — Claude Desktop وClaude Code وCursor وChatGPT وغيرها — من قراءة وكتابة بيانات نظام إدارة علاقات العملاء (CRM) لديك باستخدام اللغة الطبيعية.
استخدم **عنوان URL لمساحة العمل** (عنوان URL الذي تستخدمه للوصول إلى Twenty) كنقطة نهاية MCP. على Twenty Cloud، قد يكون عنوان URL لمساحة العمل هو `https://{mycompany}.twenty.com` أو نطاق مخصص. الخادم متاح على:
| البيئة | نقطة نهاية MCP |
| --------------------- | ---------------------------------------------------------------------------------------- |
| **السحابة** | `https://{your-workspace-url}/mcp` (على سبيل المثال: `https://mycompany.twenty.com/mcp`) |
| **الاستضافة الذاتية** | `https://{your-domain}/mcp` |
## طرق المصادقة
لديك طريقتان لمصادقة عميل MCP: **OAuth** (مُوصى بها) أو **مفتاح API**.
### الخيار أ — OAuth (مُوصى به)
باستخدام OAuth، يفتح عميل MCP لديك نافذة متصفح لتسجيل الدخول. لا يتم تخزين أي أسرار في ملفات الإعداد، ويتم تحديث الرموز المميِّزة تلقائيًا.
<Note>
يتطلب OAuth عميل MCP يدعم [مواصفة تفويض MCP](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization). تدعمه Claude Desktop وClaude Code وCursor وChatGPT.
</Note>
أضِف ما يلي إلى تهيئة عميل MCP لديك، واستبدِل `{your-workspace-url}` بمضيف مساحة العمل لديك (على سبيل المثال: `mycompany.twenty.com`):
```json
{
"mcpServers": {
"twenty": {
"type": "streamable-http",
"url": "https://{your-workspace-url}/mcp"
}
}
}
```
هذا كل شيء — لا حاجة إلى مفتاح API. عند اتصال العميل للمرة الأولى، سيفعل ما يلي:
1. اكتشاف بيانات التعريف الخاصة بـ OAuth لدى Twenty عبر `/.well-known/oauth-protected-resource` و`/.well-known/oauth-authorization-server`
2. تسجيل نفسه كعميل OAuth عبر التسجيل الديناميكي للعميل (RFC 7591)
3. فتح متصفحك لتفويض الوصول
4. استلام الرموز المميِّزة والاتصال بخادم MCP
تعيد الاتصالات اللاحقة استخدام الرموز المميِّزة المخزنة وتحدِّثها تلقائيًا.
### الخيار ب — مفتاح API
إذا كان عميل MCP لديك لا يدعم OAuth، أو كنت تفضّل بيانات اعتماد ثابتة، فمرِّر مفتاح API في ترويسة `Authorization`:
```json
{
"mcpServers": {
"twenty": {
"type": "streamable-http",
"url": "https://{your-workspace-url}/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
```
<Warning>
يمنح مفتاح API الخاص بك حق الوصول إلى بيانات مساحة العمل. أبعِده عن أنظمة التحكم في الإصدارات وملفات dotfiles المشتركة.
</Warning>
لإنشاء مفتاح API، انتقل إلى **Settings > APIs & Webhooks > + Create key**. راجع [واجهات برمجة التطبيقات](/l/ar/developers/extend/api#create-an-api-key) للتفاصيل.
## البدء السريع
### 1. انسخ الإعداد
انتقل إلى **Settings > AI > More > MCP Server** في Twenty. اختر طريقة المصادقة (OAuth أو مفتاح API)، وانسخ مقطع JSON (سيستخدم بالفعل عنوان URL لمساحة العمل لديك)، ثم الصقه في ملف إعدادات عميل MCP لديك.
| العميل | موقع ملف الإعداد |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Claude Desktop** | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) أو `%APPDATA%\Claude\claude_desktop_config.json` (Windows) |
| **Claude Code** | `~/.claude.json` (المستخدم) أو `.mcp.json` (المشروع) |
| **Cursor** | `.cursor/mcp.json` ضمن مشروعك، أو `~/.cursor/mcp.json` عالميًا |
| **ChatGPT** | فعِّل وضع المطوّر في **Settings > Apps & Connectors > Advanced settings**، ثم استخدم **Create** في **Settings > Apps & Connectors** لإضافة خادم MCP |
### 2. الاتصال
أعِد تشغيل عميل MCP لديك (أو أعد تحميل ملف الإعداد). إذا كنت تستخدم OAuth فسيتم توجيهك إلى Twenty لتفويض الوصول. إذا كنت تستخدم مفتاح API فسيكون الاتصال فوريًا.
### 3. ابدأ باستخدامه
اطلب من مساعد الذكاء الاصطناعي التفاعل مع نظام إدارة علاقات العملاء (CRM) لديك:
* *"أرني أحدث 5 شركات تم إنشاؤها"*
* *"أنشئ شخصًا جديدًا باسم Jane Doe في Acme Corp"*
* *"اعثر على جميع الفرص المفتوحة التي تزيد قيمتها عن 10 آلاف دولار"*
## الأدوات المتاحة
بعد الاتصال، يوفّر خادم MCP أدوات تعكس واجهة برمجة تطبيقات Twenty (API). سير العمل الموصى به هو:
1. **`get_tool_catalog`** — اكتشف جميع الأدوات المتاحة
2. **`learn_tools`** — احصل على مخطط الإدخال لأدوات محددة
3. **`execute_tool`** — شغّل أداة
لا تحتاج إلى تذكّر أسماء الأدوات. اسأل مساعد الذكاء الاصطناعي عمّا يمكنه فعله وسيستدعي `get_tool_catalog` تلقائيًا.
## الصلاحيات
ترث اتصالات MCP أذونات المستخدم المُصادَق عليه (OAuth) أو الدور المُعيَّن لمفتاح API. لتقييد ما يمكن لخادم MCP القيام به:
* **OAuth**: ينطبق دور المستخدم في مساحة العمل.
* **API Key**: عيِّن دورًا لمفتاح API ضمن **Settings > Roles**. راجع [الأذونات](/l/ar/user-guide/permissions-access/capabilities/permissions).
## التكوين ذاتي الاستضافة
في حالات الاستضافة الذاتية، استبدِل `{your-workspace-url}` بعنوان URL الخاص بالخادم لديك. تأكّد من أن قيمة `SERVER_URL` في بيئتك تطابق عنوان URL العام لمثيل Twenty لديك — إذ يُستخدَم ذلك لإنشاء بيانات تعريف اكتشاف OAuth.
```bash
SERVER_URL=https://twenty.yourcompany.com
```
تُشتق نقطة نهاية MCP ونقاط نهاية OAuth وبيانات تعريف الاكتشاف جميعها من هذه القيمة.
## استكشاف الأخطاء وإصلاحها
**أخطاء "Unauthorized" أو 401**
* OAuth: أعد التفويض عبر مسح الرموز المميِّزة المخزنة في عميل MCP لديك ثم أعد الاتصال.
* API Key: تحقّق من أن المفتاح صالح ولم تنتهِ صلاحيته. أعِد توليده إذا لزم الأمر.
**عملية OAuth لا تفتح متصفحًا**
* تأكّد من أن عميل MCP لديك يدعم تفويض MCP. ارجع إلى طريقة مفتاح API إذا لم يكن كذلك.
**انتهاء مهلة الاتصال**
* تحقّق من إمكانية الوصول إلى عنوان URL لنقطة نهاية MCP من جهازك. بالنسبة لحالات الاستضافة الذاتية، تحقّق من أن الخادم يعمل وأن `SERVER_URL` مُعيَّن بشكل صحيح.
@@ -6,7 +6,7 @@ description: Der Leitfaden für Mitwirkende (oder neugierige Entwickler), die Tw
## Voraussetzungen
<Tabs>
<Tab title="Linux und macOS">
<Tab title="Linux und MacOS">
Bevor Sie Twenty installieren und verwenden können, stellen Sie sicher, dass Sie Folgendes auf Ihrem Computer installiert haben:
* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
@@ -103,7 +103,7 @@ Alle folgenden Befehle innerhalb des Projekts sind vom Stammverzeichnis aus ausz
<Tabs>
<Tab title="Linux">
**Option 1 (bevorzugt):** Um Ihre Datenbank lokal bereitzustellen:
Verwenden Sie den folgenden Link, um PostgreSQL auf Ihrem Linux-Rechner zu installieren: [PostgreSQL-Installation](https://www.postgresql.org/download/linux/)
Verwenden Sie den folgenden Link, um PostgreSQL auf Ihrem Linux-Rechner zu installieren: [Postgresql-Installation](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
@@ -129,8 +129,8 @@ Alle folgenden Befehle innerhalb des Projekts sind vom Stammverzeichnis aus ausz
brew services list
```
Das Installationsprogramm erstellt den Benutzer `postgres` möglicherweise nicht standardmäßig bei der Installation
über Homebrew auf macOS. Stattdessen wird eine PostgreSQL-Rolle erstellt, die Ihrem macOS
Der Installer erstellt möglicherweise nicht standardmäßig den Benutzer `postgres`, wenn er
über Homebrew auf MacOS installiert wird. Stattdessen wird eine PostgreSQL-Rolle erstellt, die Ihrem macOS
Benutzernamen (z. B. "john") entspricht.
Um zu überprüfen und, falls erforderlich, den Benutzer `postgres` zu erstellen, führen Sie folgende Schritte aus:
```bash
@@ -174,7 +174,7 @@ Alle folgenden Befehle innerhalb des Projekts sind vom Stammverzeichnis aus ausz
Alle folgenden Schritte sind im WSL-Terminal auszuführen (innerhalb Ihrer virtuellen Maschine)
**Option 1:** Um Ihr PostgreSQL lokal bereitzustellen:
Verwenden Sie den folgenden Link, um PostgreSQL auf Ihrer Linux-VM zu installieren: [PostgreSQL-Installation](https://www.postgresql.org/download/linux/)
Verwenden Sie den folgenden Link, um PostgreSQL auf Ihrer Linux-VM zu installieren: [Postgresql-Installation](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
@@ -189,13 +189,11 @@ Alle folgenden Befehle innerhalb des Projekts sind vom Stammverzeichnis aus ausz
</Tab>
</Tabs>
Sie können nun über `localhost:5432` auf die Datenbank zugreifen.
Wenn Sie die oben genannte Docker-Option verwendet haben, lauten die Standardanmeldedaten Benutzer `postgres` und Passwort `postgres`. Für native PostgreSQL-Installationen verwenden Sie die auf Ihrem Rechner konfigurierten Anmeldedaten und Rollen.
Sie können jetzt über [localhost:5432](localhost:5432) auf die Datenbank zugreifen, mit dem Benutzer `postgres` und dem Passwort `postgres`.
## Schritt 4: Einrichten einer Redis-Datenbank (Cache)
Twenty benötigt einen Redis-Cache, um die beste Leistung zu bieten.
Twenty benötigt einen Redis-Cache, um die beste Leistung zu bieten
<Tabs>
<Tab title="Linux">
@@ -213,9 +211,7 @@ Twenty benötigt einen Redis-Cache, um die beste Leistung zu bieten.
brew install redis
```
Starten Sie Ihren Redis-Server:
```bash
brew services start redis
```
`brew services start redis`
**Option 2:** Wenn Sie Docker installiert haben:
```bash
@@ -233,11 +229,11 @@ Twenty benötigt einen Redis-Cache, um die beste Leistung zu bieten.
</Tab>
</Tabs>
Wenn Sie eine Client-GUI benötigen, empfehlen wir [Redis Insight](https://redis.io/insight/) (kostenlose Version verfügbar).
Wenn Sie eine Client-GUI benötigen, empfehlen wir [redis insight](https://redis.io/insight/) (kostenlose Version verfügbar)
## Schritt 5: Einrichten von Umgebungsvariablen
Verwenden Sie Umgebungsvariablen oder `.env`-Dateien, um Ihr Projekt zu konfigurieren. Weitere Informationen [hier](/l/de/developers/self-host/capabilities/setup).
Verwenden Sie Umgebungsvariablen oder `.env`-Dateien, um Ihr Projekt zu konfigurieren. Weitere Informationen [hier](/l/de/developers/self-host/capabilities/setup)
Kopieren Sie die `.env.example`-Dateien in `/front` und `/server`:
@@ -21,51 +21,19 @@ Mit Apps können Sie Twenty-Anpassungen **als Code** erstellen und verwalten. An
## Voraussetzungen
* Node.js 24+ und Yarn 4
* Docker (für den lokalen Twenty-Dev-Server)
* Ein Twenty-Workspace und ein API-Schlüssel (unter https://app.twenty.com/settings/api-webhooks erstellen)
## Erste Schritte
Erstelle eine neue App mit dem offiziellen Scaffolder. Der Scaffolder kann für dich automatisch eine lokale Twenty-Instanz starten:
Erstellen Sie mit dem offiziellen Scaffolder eine neue App, authentifizieren Sie sich und beginnen Sie mit der Entwicklung:
```bash filename="Terminal"
# Eine neue App erstellen — die CLI bietet an, einen lokalen Twenty-Server zu starten
# Eine neue App erstellen (enthält standardmäßig alle Beispiele)
npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
# Dev-Modus starten: synchronisiert lokale Änderungen automatisch mit deinem Arbeitsbereich
yarn twenty dev
```
### Lokale Serververwaltung
Das SDK enthält Befehle zur Verwaltung eines lokalen Twenty-Dev-Servers (All-in-One-Docker-Image mit PostgreSQL, Redis, Server und Worker):
```bash filename="Terminal"
# Den lokalen Server starten (lädt das Image bei Bedarf herunter)
yarn twenty server start
# Serverstatus prüfen
yarn twenty server status
# Serverprotokolle streamen
yarn twenty server logs
# Server stoppen
yarn twenty server stop
# Alle Daten zurücksetzen und neu starten
yarn twenty server reset
```
Der lokale Server ist bereits mit einem Arbeitsbereich und einem Benutzer (`tim@apple.dev` / `tim@apple.dev`) vorbefüllt, sodass Sie ohne manuelle Einrichtung sofort mit der Entwicklung beginnen können.
### Authentifizierung
Verbinden Sie Ihre App mithilfe von OAuth mit dem lokalen Server:
```bash filename="Terminal"
# Authenticate via OAuth (opens browser)
yarn twenty remote add --local
yarn twenty app:dev
```
Das Scaffolding-Tool unterstützt zwei Modi, um zu steuern, welche Beispieldateien enthalten sind:
@@ -96,17 +64,11 @@ yarn twenty function:execute --preInstall
# Die Post-Installationsfunktion ausführen
yarn twenty function:execute --postInstall
# Die Anwendung für die Verteilung erstellen
yarn twenty app:build
# Die Anwendung auf npm oder einen Twenty-Server veröffentlichen
yarn twenty app:publish
# Die Anwendung aus dem aktuellen Arbeitsbereich deinstallieren
yarn twenty app:uninstall
# Hilfe zu Befehlen anzeigen
yarn twenty help
yarn twenty help},{
```
Siehe auch: die CLI-Referenzseiten für [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) und [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
@@ -1278,113 +1240,6 @@ Hauptpunkte:
Ein minimales End-to-End-Beispiel, das Objekte, Logikfunktionen, Frontend-Komponenten und mehrere Trigger demonstriert, finden Sie [hier](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/hello-world):
## Erstellen Ihrer App
Sobald Sie Ihre App mit `app:dev` entwickelt haben, verwenden Sie `app:build`, um sie in ein verteilbares Paket zu kompilieren.
```bash filename="Terminal"
# Die App erstellen (Ausgabe nach .twenty/output/)
yarn twenty app:build
# Build ausführen und ein Tarball (.tgz) für die Verteilung erstellen
yarn twenty app:build --tarball
```
Der Build-Prozess:
1. **Parst und validiert das Manifest** — liest alle `defineX()`-Entitäten aus Ihren Quelldateien und validiert die Manifeststruktur.
2. **Kompiliert Logikfunktionen und Front-Komponenten** — bündelt TypeScript-Quellcode in ESM `.mjs`-Dateien mit esbuild.
3. **Erzeugt Checksummen** — berechnet MD5-Hashes für jede erstellte Datei, die im Manifest als `builtHandlerChecksum` / `builtComponentChecksum` gespeichert werden.
4. **Generiert den typisierten API-Client** — führt eine Introspektion des GraphQL-Schemas durch und generiert die typisierten Clients `CoreApiClient` und `MetadataApiClient`.
5. **Führt eine TypeScript-Typprüfung aus** — führt `tsc --noEmit` aus, um Typfehler vor der Veröffentlichung zu erkennen.
6. **Baut mit dem generierten Client neu** — führt einen zweiten Kompiliervorgang durch, damit die generierten Client-Typen enthalten sind.
7. **Erstellt optional einen Tarball** — wenn `--tarball` übergeben wird, wird `npm pack` ausgeführt, um eine `.tgz`-Datei zu erstellen, die für die Verteilung bereit ist.
Der Build-Output in `.twenty/output/` enthält:
```text
.twenty/output/
├── manifest.json # Manifest with checksums for all built files
├── package.json # Copied from app root
├── yarn.lock # Copied from app root
├── src/
│ ├── logic-functions/ # Compiled .mjs logic function files
│ └── front-components/ # Compiled .mjs front component files
├── public/ # Static assets (if any)
└── my-app-1.0.0.tgz # Only with --tarball flag
```
| Option | Beschreibung |
| ----------- | -------------------------------------------------------------- |
| `[appPath]` | Pfad zum App-Verzeichnis (standardmäßig aktuelles Verzeichnis) |
| `--tarball` | Den Output zusätzlich in einen `.tgz`-Tarball packen |
## Veröffentlichen Ihrer App
Verwenden Sie `app:publish`, um Ihre App zu verteilen — entweder zur npm-Registry oder direkt zu einem Twenty-Server.
### Bei npm veröffentlichen (Standard)
```bash filename="Terminal"
# Publish to npm (requires npm login)
yarn twenty app:publish
# Publish with a dist-tag (e.g. beta, next)
yarn twenty app:publish --tag beta
```
Dies baut die App und führt `npm publish` aus dem Verzeichnis `.twenty/output/` aus. Das veröffentlichte Paket kann dann von jedem Arbeitsbereich über den Twenty-Marktplatz installiert werden.
### Auf einem Twenty-Server veröffentlichen
```bash filename="Terminal"
# Publish directly to a Twenty server
yarn twenty app:publish --server https://app.twenty.com
```
Dies erstellt beim Build einen Tarball, lädt ihn über die GraphQL-Mutation `uploadAppTarball` auf den Server hoch und stößt die Installation in einem Schritt an. Dies ist nützlich für private Bereitstellungen oder Tests gegen einen bestimmten Server.
| Option | Beschreibung |
| ----------------- | ------------------------------------------------------------------ |
| `[appPath]` | Pfad zum App-Verzeichnis (standardmäßig aktuelles Verzeichnis) |
| `--server <url>` | Auf einen Twenty-Server anstelle von npm veröffentlichen |
| `--token <token>` | Authentifizierungstoken für den Zielserver |
| `--tag <tag>` | npm dist-tag (z. B. `beta`, `next`) — nur für npm-Veröffentlichung |
## Anwendungsregistrierung
Bevor eine App in einem Arbeitsbereich installiert werden kann, muss sie **registriert** werden. Eine Registrierung ist ein Metadatensatz, der beschreibt, woher die App stammt und wie sie authentifiziert wird. Dies wird in den meisten Fällen automatisch durch die CLI erledigt.
### Quelltypen
Jede Registrierung hat einen **Quelltyp**, der bestimmt, wie die Dateien der App während der Installation aufgelöst werden:
| Quelltyp | Wie Dateien aufgelöst werden | Typischer Anwendungsfall |
| --------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `LOCAL` | Dateien werden in Echtzeit vom CLI-Watcher synchronisiert — die Installation wird übersprungen | Entwicklung mit `app:dev` |
| `NPM` | Über das Feld `sourcePackage` aus der npm-Registry abgerufen | Veröffentlichte Apps auf npm |
| `TARBALL` | Aus einer hochgeladenen, auf dem Server gespeicherten `.tgz`-Datei extrahiert | Private Apps, die mit `--server` veröffentlicht wurden |
### Wie die Registrierung erfolgt
* **`app:dev`** — erstellt beim ersten Ausführen des Dev-Modus für einen Arbeitsbereich automatisch eine `LOCAL`-Registrierung.
* **`app:publish --server`** — lädt einen Tarball hoch und erstellt (oder aktualisiert) eine `TARBALL`-Registrierung und installiert anschließend die App.
* **npm-Marktplatz** — `NPM`-Registrierungen werden erstellt, wenn Apps aus der npm-Registry in den Twenty-Marktplatzkatalog synchronisiert werden.
* **GraphQL-API** — Sie können Registrierungen auch programmgesteuert über die Mutation `createApplicationRegistration` erstellen.
### Registrierung vs. Installation
**Registrierung** und **Installation** sind unterschiedliche Konzepte:
* Eine **Registrierung** (`ApplicationRegistration`) ist ein globaler Metadatensatz, der die App beschreibt: ihren Namen, den Quelltyp, die OAuth-Anmeldedaten und den Status der Marktplatzlistung. Sie existiert unabhängig von jedem Arbeitsbereich.
* Eine **Installation** (`Application`) ist eine Instanz pro Arbeitsbereich. Wenn ein Benutzer eine App installiert, ermittelt Twenty das Paket aus der Quelle der Registrierung, schreibt die erstellten Dateien in den Speicher und synchronisiert das Manifest (wobei Objekte, Felder, Logikfunktionen usw. erstellt werden) in diesem Arbeitsbereich.
Eine Registrierung kann in vielen Arbeitsbereichen installiert werden. Jeder Arbeitsbereich erhält seine eigene Kopie der Dateien und des Datenmodells der App.
### OAuth-Anmeldedaten
Jede Registrierung enthält OAuth-Anmeldedaten (`oAuthClientId` und `oAuthClientSecret`), die bei der Erstellung generiert werden. Diese werden von der App verwendet, um API-Anfragen im Namen der Benutzer zu authentifizieren. Das Client-Secret wird bei der Erstellung **einmalig** zurückgegeben — bewahren Sie es sicher auf. Sie können es später über die Mutation `rotateApplicationRegistrationClientSecret` rotieren.
## Manuelle Einrichtung (ohne Scaffolder)
Wir empfehlen zwar `create-twenty-app` für das beste Einstiegserlebnis, Sie können ein Projekt aber auch manuell einrichten. Installieren Sie die CLI nicht global. Fügen Sie stattdessen `twenty-sdk` als lokale Abhängigkeit hinzu und binden Sie ein einzelnes Skript in Ihrer package.json ein:
@@ -3,7 +3,7 @@ title: 1-Klick mit Docker Compose
---
<Warning>
Docker-Container sind für produktives Hosting oder Selbsthosting vorgesehen. Zum Mitwirken siehe [Lokale Einrichtung](/l/de/developers/contribute/capabilities/local-setup).
Docker-Container sind für die Produktion oder das Selbsthosten bestimmt. Für Beiträge siehe bitte das [Lokale Setup](/l/de/developers/contribute/capabilities/local-setup).
</Warning>
## Überblick
@@ -12,7 +12,7 @@ Diese Anleitung enthält Schritt-für-Schritt-Anweisungen, um die Twenty-Anwendu
**Wichtig:** Ändern Sie nur die in dieser Anleitung explizit erwähnten Einstellungen. Andere Konfigurationen zu ändern, kann zu Problemen führen.
Siehe die Dokumentation [Umgebungsvariablen einrichten](/l/de/developers/self-host/capabilities/setup) zur erweiterten Konfiguration. Alle Umgebungsvariablen müssen in der Datei `docker-compose.yml` auf Server- und/oder Worker-Ebene deklariert werden, je nach Variable.
Siehe die Dokumentation [Umgebungsvariablen einrichten](/l/de/developers/self-host/capabilities/setup) zur erweiterten Konfiguration. Alle Umgebungsvariablen müssen in der Datei docker-compose.yml auf Server- und/oder Worker-Ebene deklariert werden, je nach Variable.
## Systemanforderungen
@@ -297,60 +297,46 @@ yarn command:prod cron:workflow:automated-cron-trigger
**Nur-Umgebungsmodus:** Wenn Sie `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false` setzen, fügen Sie diese Variablen stattdessen Ihrer `.env`-Datei hinzu.
</Warning>
## Logikfunktionen & Code-Interpreter
## Logikfunktionen
Twenty unterstützt Logikfunktionen für Workflows und den Code-Interpreter für KI-Datenanalyse. Beide führen vom Benutzer bereitgestellten Code aus und erfordern aus Sicherheitsgründen eine explizite Konfiguration.
### Sicherheits-Standardeinstellungen
**In Produktion (NODE_ENV=production):** Sowohl Logikfunktionen als auch der Code-Interpreter sind standardmäßig **deaktiviert**. Sie müssen sie, wenn Sie diese Funktionen benötigen, explizit mit `LOGIC_FUNCTION_TYPE` und `CODE_INTERPRETER_TYPE` aktivieren.
**In der Entwicklung (NODE_ENV=development):** Beide sind der Einfachheit halber beim lokalen Betrieb standardmäßig **LOCAL**.
Twenty unterstützt Logikfunktionen für Workflows und benutzerdefinierte Logik. Die Ausführungsumgebung wird über die Umgebungsvariable `SERVERLESS_TYPE` konfiguriert.
<Warning>
**Sicherheitshinweis:** Der lokale Treiber (`LOGIC_FUNCTION_TYPE=LOCAL` oder `CODE_INTERPRETER_TYPE=LOCAL`) führt Code ohne Sandbox direkt auf dem Host in einem Node.js-Prozess aus. Er sollte nur für vertrauenswürdigen Code in der Entwicklung verwendet werden. Für Produktionsbereitstellungen, die nicht vertrauenswürdigen Code verarbeiten, verwenden Sie `LOGIC_FUNCTION_TYPE=LAMBDA` oder `CODE_INTERPRETER_TYPE=E2B` (mit Sandbox-Isolierung), oder lassen Sie sie deaktiviert.
**Sicherheitshinweis:** Der lokale Treiber (`SERVERLESS_TYPE=LOCAL`) führt Code ohne Sandbox direkt auf dem Host in einem Node.js-Prozess aus. Er sollte nur für vertrauenswürdigen Code in der Entwicklung verwendet werden. Für Produktivbereitstellungen, die nicht vertrauenswürdigen Code verarbeiten, empfehlen wir nachdrücklich, `SERVERLESS_TYPE=LAMBDA` oder `SERVERLESS_TYPE=DISABLED` zu verwenden.
</Warning>
### Logikfunktionen - Verfügbare Treiber
### Verfügbare Treiber
| Treiber | Umgebungsvariable | Anwendungsfall | Sicherheitsstufe |
| ----------- | ------------------------------ | -------------------------------------------------- | ---------------------------------- |
| Deaktiviert | `LOGIC_FUNCTION_TYPE=DISABLED` | Logikfunktionen vollständig deaktivieren | N/A |
| Lokal | `LOGIC_FUNCTION_TYPE=LOCAL` | Entwicklung und vertrauenswürdige Umgebungen | Niedrig (keine Sandbox) |
| Lambda | `LOGIC_FUNCTION_TYPE=LAMBDA` | Produktivbetrieb mit nicht vertrauenswürdigem Code | Hoch (Isolation auf Hardwareebene) |
| Treiber | Umgebungsvariable | Anwendungsfall | Sicherheitsstufe |
| ----------- | -------------------------- | -------------------------------------------------- | ---------------------------------- |
| Deaktiviert | `SERVERLESS_TYPE=DISABLED` | Logikfunktionen vollständig deaktivieren | N/A |
| Lokal | `SERVERLESS_TYPE=LOCAL` | Entwicklung und vertrauenswürdige Umgebungen | Niedrig (keine Sandbox) |
| Lambda | `SERVERLESS_TYPE=LAMBDA` | Produktivbetrieb mit nicht vertrauenswürdigem Code | Hoch (Isolation auf Hardwareebene) |
### Logikfunktionen - Empfohlene Konfiguration
### Empfohlene Konfiguration
**Für die Entwicklung:**
```bash
LOGIC_FUNCTION_TYPE=LOCAL # default when NODE_ENV=development
SERVERLESS_TYPE=LOCAL # default
```
**Für den Produktivbetrieb (AWS):**
```bash
LOGIC_FUNCTION_TYPE=LAMBDA
LOGIC_FUNCTION_LAMBDA_REGION=us-east-1
LOGIC_FUNCTION_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID=your-access-key
LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
SERVERLESS_TYPE=LAMBDA
SERVERLESS_LAMBDA_REGION=us-east-1
SERVERLESS_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
SERVERLESS_LAMBDA_ACCESS_KEY_ID=your-access-key
SERVERLESS_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
```
**Zum Deaktivieren von Logikfunktionen:**
```bash
LOGIC_FUNCTION_TYPE=DISABLED # default when NODE_ENV=production
SERVERLESS_TYPE=DISABLED
```
### Code-Interpreter - Verfügbare Treiber
| Treiber | Umgebungsvariable | Anwendungsfall | Sicherheitsstufe |
| ----------- | -------------------------------- | ------------------------------------------ | ------------------------ |
| Deaktiviert | `CODE_INTERPRETER_TYPE=DISABLED` | KI-Codeausführung deaktivieren | N/A |
| Lokal | `CODE_INTERPRETER_TYPE=LOCAL` | Nur für die Entwicklung | Niedrig (keine Sandbox) |
| E2B | `CODE_INTERPRETER_TYPE=E_2_B` | Produktion mit Ausführung in einer Sandbox | Hoch (isolierte Sandbox) |
<Note>
Bei Verwendung von `LOGIC_FUNCTION_TYPE=DISABLED` oder `CODE_INTERPRETER_TYPE=DISABLED` führt jeder Ausführungsversuch zu einem Fehler. Dies ist nützlich, wenn Sie Twenty ohne diese Funktionen betreiben möchten.
Bei Verwendung von `SERVERLESS_TYPE=DISABLED` führt jeder Versuch, eine Logikfunktion auszuführen, zu einem Fehler. Dies ist nützlich, wenn Sie Twenty ohne Unterstützung für Logikfunktionen betreiben möchten.
</Note>
@@ -1,142 +0,0 @@
---
title: MCP-Server
description: Verbinden Sie KI-Assistenten mit Ihrem Twenty-Workspace über das Model Context Protocol.
---
<Warning>
MCP befindet sich derzeit in **alpha** und ist nur in einigen Workspaces verfügbar. Möglicherweise ist es für Ihren Workspace noch nicht aktiviert.
</Warning>
Twenty stellt einen [MCP](https://modelcontextprotocol.io/)-Server bereit, damit KI-Assistenten — Claude Desktop, Claude Code, Cursor, ChatGPT und andere — Ihre CRM-Daten in natürlicher Sprache lesen und schreiben können.
Verwenden Sie Ihre **Workspace-URL** (die URL, mit der Sie auf Twenty zugreifen) als MCP-Endpunkt. In Twenty Cloud kann Ihre Workspace-URL `https://{mycompany}.twenty.com` oder eine benutzerdefinierte Domain sein. Der Server ist verfügbar unter:
| Umgebung | MCP-Endpunkt |
| ----------------- | ----------------------------------------------------------------------------- |
| **Cloud** | `https://{your-workspace-url}/mcp` (z. B. `https://mycompany.twenty.com/mcp`) |
| **Selbsthosting** | `https://{your-domain}/mcp` |
## Authentifizierungsmethoden
Sie haben zwei Möglichkeiten, Ihren MCP-Client zu authentifizieren: **OAuth** (empfohlen) oder **API-Schlüssel**.
### Option A — OAuth (empfohlen)
Mit OAuth öffnet Ihr MCP-Client ein Browserfenster, damit Sie sich anmelden können. Es werden keine geheimen Informationen in Konfigurationsdateien gespeichert, und Token werden automatisch erneuert.
<Note>
OAuth erfordert einen MCP-Client, der die [MCP-Autorisierungsspezifikation](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) unterstützt. Claude Desktop, Claude Code, Cursor und ChatGPT unterstützen dies.
</Note>
Fügen Sie dies zu Ihrer MCP-Client-Konfiguration hinzu und ersetzen Sie `{your-workspace-url}` durch den Host Ihrer Workspace-URL (z. B. `mycompany.twenty.com`):
```json
{
"mcpServers": {
"twenty": {
"type": "streamable-http",
"url": "https://{your-workspace-url}/mcp"
}
}
}
```
Das ist alles — kein API-Schlüssel erforderlich. Wenn der Client sich zum ersten Mal verbindet, wird er:
1. Die OAuth-Metadaten von Twenty über `/.well-known/oauth-protected-resource` und `/.well-known/oauth-authorization-server` ermitteln
2. Sich über die dynamische Client-Registrierung (RFC 7591) als OAuth-Client registrieren
3. Ihren Browser öffnen, um den Zugriff zu autorisieren
4. Token empfangen und eine Verbindung zum MCP-Server herstellen
Nachfolgende Verbindungen verwenden die gespeicherten Token erneut und erneuern sie automatisch.
### Option B — API-Schlüssel
Wenn Ihr MCP-Client OAuth nicht unterstützt oder Sie statische Anmeldeinformationen bevorzugen, übergeben Sie einen API-Schlüssel im `Authorization`-Header:
```json
{
"mcpServers": {
"twenty": {
"type": "streamable-http",
"url": "https://{your-workspace-url}/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
```
<Warning>
Ihr API-Schlüssel gewährt Zugriff auf Workspace-Daten. Halten Sie es von der Versionskontrolle und von gemeinsam genutzten Dotfiles fern.
</Warning>
Um einen API-Schlüssel zu erstellen, gehen Sie zu **Settings > APIs & Webhooks > + Create key**. Details finden Sie unter [APIs](/l/de/developers/extend/api#create-an-api-key).
## Schnellstart
### 1. Konfiguration kopieren
Gehen Sie in Twenty zu **Settings > AI > More > MCP Server**. Wählen Sie Ihre Authentifizierungsmethode (OAuth oder API-Schlüssel), kopieren Sie das JSON-Snippet (es verwendet bereits Ihre Workspace-URL) und fügen Sie es in die Konfigurationsdatei Ihres MCP-Clients ein.
| Client | Speicherort der Konfigurationsdatei |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Claude Desktop** | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) oder `%APPDATA%\Claude\claude_desktop_config.json` (Windows) |
| **Claude Code** | `~/.claude.json` (Benutzer) oder `.mcp.json` (Projekt) |
| **Cursor** | `.cursor/mcp.json` in Ihrem Projekt oder `~/.cursor/mcp.json` global |
| **ChatGPT** | Aktivieren Sie den Entwicklermodus in **Settings > Apps & Connectors > Advanced settings** und verwenden Sie dann **Create** in **Settings > Apps & Connectors**, um den MCP-Server hinzuzufügen |
### 2. Verbinden
Starten Sie Ihren MCP-Client neu (oder laden Sie die Konfiguration neu). Bei Verwendung von OAuth werden Sie zu Twenty weitergeleitet, um den Zugriff zu autorisieren. Bei Verwendung eines API-Schlüssels wird die Verbindung sofort hergestellt.
### 3. Jetzt loslegen
Bitten Sie Ihren KI-Assistenten, mit Ihrem CRM zu interagieren:
* *"Zeige mir die 5 zuletzt erstellten Unternehmen"*
* *"Erstelle eine neue Person namens Jane Doe bei Acme Corp"*
* *"Finde alle offenen Verkaufschancen mit einem Wert von mehr als $10k"*
## Verfügbare Tools
Nach der Verbindung stellt der MCP-Server Tools bereit, die die Twenty-API widerspiegeln. Der empfohlene Workflow ist:
1. **`get_tool_catalog`** — alle verfügbaren Tools entdecken
2. **`learn_tools`** — das Eingabeschema für bestimmte Tools abrufen
3. **`execute_tool`** — ein Tool ausführen
Sie müssen sich die Tool-Namen nicht merken. Fragen Sie Ihren KI-Assistenten, was er tun kann, und er ruft `get_tool_catalog` automatisch auf.
## Berechtigungen
MCP-Verbindungen erben die Berechtigungen des authentifizierten Benutzers (OAuth) oder die dem API-Schlüssel zugewiesene Rolle. So beschränken Sie, was der MCP-Server tun darf:
* **OAuth**: Es gilt die Workspace-Rolle des Benutzers.
* **API-Schlüssel**: Weisen Sie dem API-Schlüssel unter **Settings > Roles** eine Rolle zu. Siehe [Berechtigungen](/l/de/user-guide/permissions-access/capabilities/permissions).
## Selbstgehostete Konfiguration
Für selbstgehostete Instanzen ersetzen Sie `{your-workspace-url}` durch die URL Ihres Servers. Stellen Sie sicher, dass `SERVER_URL` in Ihrer Umgebung der öffentlichen URL Ihrer Twenty-Instanz entspricht — dieser Wert wird verwendet, um die OAuth-Discovery-Metadaten zu generieren.
```bash
SERVER_URL=https://twenty.yourcompany.com
```
Der MCP-Endpunkt, die OAuth-Endpunkte und die Discovery-Metadaten leiten sich alle von diesem Wert ab.
## Fehlerbehebung
**"Unauthorized"- oder 401-Fehler**
* OAuth: Autorisieren Sie erneut, indem Sie die gespeicherten Token in Ihrem MCP-Client löschen und die Verbindung wiederherstellen.
* API-Schlüssel: Überprüfen Sie, ob der Schlüssel gültig ist und nicht abgelaufen ist. Generieren Sie ihn bei Bedarf neu.
**Der OAuth-Flow öffnet keinen Browser**
* Stellen Sie sicher, dass Ihr MCP-Client MCP Authorization unterstützt. Wechseln Sie andernfalls zur API-Schlüssel-Methode.
**Verbindungszeitüberschreitung**
* Stellen Sie sicher, dass die MCP-Endpunkt-URL von Ihrem Rechner aus erreichbar ist. Bei selbstgehosteten Instanzen prüfen Sie, ob der Server läuft und `SERVER_URL` korrekt gesetzt ist.
@@ -6,7 +6,7 @@ description: La guida per i collaboratori (o sviluppatori curiosi) che vogliono
## Prerequisiti
<Tabs>
<Tab title="Linux e macOS">
<Tab title="Linux e MacOS">
Prima di poter installare e usare Twenty, assicurati di installare quanto segue sul tuo computer:
* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
@@ -129,8 +129,8 @@ Dovresti eseguire tutti i comandi nei passaggi successivi dalla radice del proge
brew services list
```
Il programma di installazione potrebbe non creare l'utente `postgres` per impostazione predefinita quando si installa
tramite Homebrew su macOS. Invece, crea un ruolo di PostgreSQL che corrisponde al tuo nome utente macOS
L'installatore potrebbe non creare l'utente `postgres` di default quando si installa
tramite Homebrew su MacOS. Invece, crea un ruolo di PostgreSQL che corrisponde al tuo nome utente macOS
(es., "john").
Per controllare e creare l'utente `postgres` se necessario, segui questi passaggi:
```bash
@@ -174,7 +174,7 @@ Dovresti eseguire tutti i comandi nei passaggi successivi dalla radice del proge
Tutti i passaggi seguenti devono essere eseguiti nel terminale WSL (all'interno della tua macchina virtuale)
**Opzione 1:** Per predisporre PostgreSQL in locale:
Usa il seguente link per installare PostgreSQL sulla tua macchina virtuale Linux: [Installazione di PostgreSQL](https://www.postgresql.org/download/linux/)
Usa il seguente link per installare PostgreSQL nella tua macchina virtuale Linux: [Installazione di PostgreSQL](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
@@ -189,13 +189,11 @@ Dovresti eseguire tutti i comandi nei passaggi successivi dalla radice del proge
</Tab>
</Tabs>
Ora puoi accedere al database all'indirizzo `localhost:5432`.
Se hai utilizzato l'opzione Docker sopra, le credenziali predefinite sono utente `postgres` e password `postgres`. Per le installazioni native di PostgreSQL, usa le credenziali e i ruoli configurati sulla tua macchina.
Puoi ora accedere al database su [localhost:5432](localhost:5432), con utente `postgres` e password `postgres`.
## Passaggio 4: Configura un database Redis (cache)
Twenty richiede una cache Redis per offrire le migliori prestazioni.
Twenty richiede una cache Redis per offrire le migliori prestazioni
<Tabs>
<Tab title="Linux">
@@ -213,9 +211,7 @@ Twenty richiede una cache Redis per offrire le migliori prestazioni.
brew install redis
```
Avvia il tuo server Redis:
```bash
brew services start redis
```
`brew services start redis`
**Opzione 2:** Se hai Docker installato:
```bash
@@ -233,11 +229,11 @@ Twenty richiede una cache Redis per offrire le migliori prestazioni.
</Tab>
</Tabs>
Se hai bisogno di una GUI client, ti consigliamo [Redis Insight](https://redis.io/insight/) (versione gratuita disponibile).
Se hai bisogno di una GUI client, ti consigliamo [Redis Insight](https://redis.io/insight/) (versione gratuita disponibile)
## Passaggio 5: Configura le variabili d'ambiente
Usa variabili d'ambiente o file `.env` per configurare il tuo progetto. Maggiori informazioni [qui](/l/it/developers/self-host/capabilities/setup).
Usa variabili d'ambiente o file `.env` per configurare il tuo progetto. Maggiori informazioni [qui](/l/it/developers/self-host/capabilities/setup)
Copia i file `.env.example` in `/front` e `/server`:
@@ -21,51 +21,19 @@ Le app ti consentono di creare e gestire le personalizzazioni di Twenty **come c
## Prerequisiti
* Node.js 24+ e Yarn 4
* Docker (per il server di sviluppo locale di Twenty)
* Uno spazio di lavoro Twenty e una chiave API (creane una su https://app.twenty.com/settings/api-webhooks)
## Per iniziare
Crea una nuova app utilizzando lo scaffolder ufficiale. Può avviare automaticamente un'istanza locale di Twenty per te:
Crea una nuova app utilizzando lo scaffolder ufficiale, quindi autenticati e inizia a sviluppare:
```bash filename="Terminal"
# Crea lo scaffold di una nuova app — la CLI offrirà di avviare un server locale di Twenty
# Crea lo scaffold di una nuova app (include tutti gli esempi per impostazione predefinita)
npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
# Avvia la modalità di sviluppo: sincronizza automaticamente le modifiche locali con il tuo workspace
yarn twenty dev
```
### Gestione del server locale
L'SDK include comandi per gestire un server di sviluppo locale di Twenty (immagine Docker all-in-one con PostgreSQL, Redis, server e worker):
```bash filename="Terminal"
# Avvia il server locale (scarica l'immagine se necessario)
yarn twenty server start
# Verifica lo stato del server
yarn twenty server status
# Segui i log del server
yarn twenty server logs
# Arresta il server
yarn twenty server stop
# Reimposta tutti i dati e riparti da zero
yarn twenty server reset
```
Il server locale è preconfigurato con uno spazio di lavoro e un utente (`tim@apple.dev` / `tim@apple.dev`), così puoi iniziare a sviluppare immediatamente senza alcuna configurazione manuale.
### Autenticazione
Collega la tua app al server locale tramite OAuth:
```bash filename="Terminal"
# Autenticati tramite OAuth (apre il browser)
yarn twenty remote add --local
yarn twenty app:dev
```
Lo strumento di scaffolding supporta due modalità per controllare quali file di esempio vengono inclusi:
@@ -96,12 +64,6 @@ yarn twenty function:execute --preInstall
# Esegui la funzione post-installazione
yarn twenty function:execute --postInstall
# Compila l'app per la distribuzione
yarn twenty app:build
# Pubblica l'app su npm o su un server Twenty
yarn twenty app:publish
# Disinstalla l'applicazione dallo spazio di lavoro corrente
yarn twenty app:uninstall
@@ -1278,113 +1240,6 @@ Punti chiave:
Esplora un esempio minimale end-to-end che dimostra oggetti, funzioni logiche, componenti front-end e trigger multipli [qui](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/hello-world):
## Compilazione della tua app
Una volta che hai sviluppato la tua app con `app:dev`, usa `app:build` per compilarla in un pacchetto distribuibile.
```bash filename="Terminal"
# Compila l'app (l'output va in .twenty/output/)
yarn twenty app:build
# Compila e crea un tarball (.tgz) per la distribuzione
yarn twenty app:build --tarball
```
Il processo di compilazione:
1. **Analizza e convalida il manifest** — legge tutte le entità `defineX()` dai tuoi file sorgente e convalida la struttura del manifest.
2. **Compila le funzioni di logica e i componenti front-end** — raggruppa i sorgenti TypeScript in file ESM `.mjs` usando esbuild.
3. **Genera i checksum** — calcola gli hash MD5 per ogni file compilato, memorizzati nel manifest come `builtHandlerChecksum` / `builtComponentChecksum`.
4. **Genera il client API tipizzato** — esegue l'analisi dello schema GraphQL e genera i client tipizzati `CoreApiClient` e `MetadataApiClient`.
5. **Esegue un controllo dei tipi di TypeScript** — esegue `tsc --noEmit` per intercettare gli errori di tipo prima della pubblicazione.
6. **Ricompila con il client generato** — esegue una seconda passata di compilazione in modo da includere i tipi del client generato.
7. **Crea facoltativamente un tarball** — se viene passato `--tarball`, esegue `npm pack` per creare un file `.tgz` pronto per la distribuzione.
L'output della build in `.twenty/output/` contiene:
```text
.twenty/output/
├── manifest.json # Manifest con checksum per tutti i file compilati
├── package.json # Copiato dalla radice dell'app
├── yarn.lock # Copiato dalla radice dell'app
├── src/
│ ├── logic-functions/ # File .mjs compilati delle funzioni logiche
│ └── front-components/ # File .mjs compilati dei componenti front-end
├── public/ # Asset statici (se presenti)
└── my-app-1.0.0.tgz # Solo con il flag --tarball
```
| Opzione | Descrizione |
| ----------- | ------------------------------------------------------------------- |
| `[appPath]` | Percorso della directory dell'app (predefinito: directory corrente) |
| `--tarball` | Imballa anche l'output in un tarball `.tgz` |
## Pubblicazione della tua app
Usa `app:publish` per distribuire la tua app — al registro npm oppure direttamente a un server Twenty.
### Pubblica su npm (predefinito)
```bash filename="Terminal"
# Pubblica su npm (richiede l'accesso a npm)
yarn twenty app:publish
# Pubblica con un dist-tag (ad es. beta, next)
yarn twenty app:publish --tag beta
```
Questo compila l'app ed esegue `npm publish` dalla directory `.twenty/output/`. Il pacchetto pubblicato può quindi essere installato dal marketplace di Twenty da qualsiasi area di lavoro.
### Pubblica su un server Twenty
```bash filename="Terminal"
# Pubblica direttamente su un server Twenty
yarn twenty app:publish --server https://app.twenty.com
```
Questo compila l'app con un tarball, lo carica sul server tramite la mutation GraphQL `uploadAppTarball` e avvia l'installazione in un unico passaggio. Questo è utile per distribuzioni private o per effettuare test su un server specifico.
| Opzione | Descrizione |
| ----------------- | -------------------------------------------------------------------------- |
| `[appPath]` | Percorso della directory dell'app (predefinito: directory corrente) |
| `--server <url>` | Pubblica su un server Twenty invece di npm |
| `--token <token>` | Token di autenticazione per il server di destinazione |
| `--tag <tag>` | dist-tag di npm (ad es. `beta`, `next`) — solo per la pubblicazione su npm |
## Registrazione dell'applicazione
Prima che un'app possa essere installata in un'area di lavoro, deve essere **registrata**. Una registrazione è un record di metadati che descrive l'origine dell'app e come autenticarla. Nella maggior parte dei casi questo è gestito automaticamente dalla CLI.
### Tipi di origine
Ogni registrazione ha un **tipo di origine** che determina come vengono risolti i file dell'app durante l'installazione:
| Tipo di origine | Come vengono risolti i file | Caso d'uso tipico |
| --------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------- |
| `LOCAL` | I file sono sincronizzati in tempo reale dal watcher della CLI — l'installazione viene saltata | Sviluppo con `app:dev` |
| `NPM` | Recuperati dal registro npm tramite il campo `sourcePackage` | App pubblicate su npm |
| `TARBALL` | Estratti da un file `.tgz` caricato e archiviato sul server | App private pubblicate con `--server` |
### Come avviene la registrazione
* **`app:dev`** — crea automaticamente una registrazione `LOCAL` la prima volta che esegui la modalità di sviluppo su un'area di lavoro.
* **`app:publish --server`** — carica un tarball e crea (o aggiorna) una registrazione `TARBALL`, quindi installa l'app.
* **Marketplace npm** — le registrazioni `NPM` vengono create quando le app vengono sincronizzate dal registro npm nel catalogo del marketplace di Twenty.
* **GraphQL API** — puoi anche creare registrazioni in modo programmatico tramite la mutation `createApplicationRegistration`.
### Registrazione vs installazione
**Registrazione** e **installazione** sono concetti distinti:
* Una **registrazione** (`ApplicationRegistration`) è un record di metadati globale che descrive l'app: il suo nome, il tipo di origine, le credenziali OAuth e lo stato di pubblicazione nel marketplace. Esiste indipendentemente da qualsiasi area di lavoro.
* Un'**installazione** (`Application`) è un'istanza per area di lavoro. Quando un utente installa un'app, Twenty risolve il pacchetto dalla sorgente della registrazione, scrive i file compilati nell'archiviazione e sincronizza il manifest (creando oggetti, campi, funzioni logiche, ecc.) in quell'area di lavoro.
Una registrazione può essere installata in molte aree di lavoro. Ogni area di lavoro ottiene la propria copia dei file dell'app e del modello di dati.
### Credenziali OAuth
Ogni registrazione include credenziali OAuth (`oAuthClientId` e `oAuthClientSecret`) generate al momento della creazione. Queste vengono utilizzate dall'app per autenticare le richieste API per conto degli utenti. Il client secret viene restituito **una sola volta** alla creazione — conservalo in modo sicuro. Puoi ruotarlo in seguito tramite la mutation `rotateApplicationRegistrationClientSecret`.
## Configurazione manuale (senza lo scaffolder)
Sebbene consigliamo di utilizzare `create-twenty-app` per la migliore esperienza iniziale, puoi anche configurare un progetto manualmente. Non installare la CLI globalmente. Invece, aggiungi `twenty-sdk` come dipendenza locale e collega un unico script nel tuo package.json:
@@ -3,7 +3,7 @@ title: 1-Click con Docker Compose
---
<Warning>
I container Docker sono destinati all'hosting in produzione o al self-hosting. Per contribuire, consulta [Configurazione locale](/l/it/developers/contribute/capabilities/local-setup).
I container Docker sono per hosting in produzione o auto-hosting, per il contributo consulta il [Setup Locale](/l/it/developers/contribute/capabilities/local-setup).
</Warning>
## Panoramica
@@ -12,7 +12,7 @@ Questa guida fornisce istruzioni passo passo per installare e configurare l'appl
**Importante:** Modifica solo le impostazioni esplicitamente menzionate in questa guida. Modificare altre configurazioni potrebbe portare a problemi.
Consulta [Configurazione delle variabili di ambiente](/l/it/developers/self-host/capabilities/setup) per configurazioni avanzate. Tutte le variabili di ambiente devono essere dichiarate nel file `docker-compose.yml` a livello di server e/o di worker, a seconda della variabile.
Consulta i documenti [Configurazione delle Variabili di Ambiente](/l/it/developers/self-host/capabilities/setup) per configurazioni avanzate. Tutte le variabili di ambiente devono essere dichiarate nel file docker-compose.yml a livello di server e/o di worker a seconda della variabile.
## Requisiti di Sistema
@@ -296,60 +296,46 @@ yarn command:prod cron:workflow:automated-cron-trigger
**Modalità solo ambiente:** Se imposti `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false`, aggiungi queste variabili al tuo file `.env` invece.
</Warning>
## Funzioni logiche & interprete del codice
## Funzioni logiche
Twenty supporta le funzioni logiche per i workflow e l'interprete del codice per l'analisi dei dati con IA. Entrambi eseguono codice fornito dall'utente e richiedono una configurazione esplicita per motivi di sicurezza.
### Impostazioni di sicurezza predefinite
**In produzione (NODE_ENV=production):** Sia le funzioni logiche sia l'interprete del codice hanno come impostazione predefinita **Disabilitato**. È necessario abilitarli esplicitamente con `LOGIC_FUNCTION_TYPE` e `CODE_INTERPRETER_TYPE` se queste funzionalità sono necessarie.
**In sviluppo (NODE_ENV=development):** Entrambi sono impostati su **LOCAL** per comodità quando vengono eseguiti in locale.
Twenty supporta le funzioni logiche per i workflow e la logica personalizzata. L'ambiente di esecuzione è configurato tramite la variabile di ambiente `SERVERLESS_TYPE`.
<Warning>
**Avviso di sicurezza:** Il driver locale (`LOGIC_FUNCTION_TYPE=LOCAL` o `CODE_INTERPRETER_TYPE=LOCAL`) esegue il codice direttamente sull'host in un processo Node.js senza sandboxing. Dovrebbe essere utilizzato solo per codice attendibile in fase di sviluppo. Per le distribuzioni in produzione che gestiscono codice non affidabile, usa `LOGIC_FUNCTION_TYPE=LAMBDA` o `CODE_INTERPRETER_TYPE=E2B` (con sandboxing), oppure lasciali disabilitati.
**Avviso di sicurezza:** Il driver locale (`SERVERLESS_TYPE=LOCAL`) esegue il codice direttamente sull'host in un processo Node.js senza sandboxing. Dovrebbe essere utilizzato solo per codice attendibile in fase di sviluppo. Per le distribuzioni in produzione che gestiscono codice non attendibile, consigliamo vivamente di usare `SERVERLESS_TYPE=LAMBDA` o `SERVERLESS_TYPE=DISABLED`.
</Warning>
### Funzioni logiche - Driver disponibili
### Driver disponibili
| Driver | Variabile di ambiente | Caso d'uso | Livello di sicurezza |
| ------------ | ------------------------------ | -------------------------------------------- | ------------------------------------ |
| Disabilitato | `LOGIC_FUNCTION_TYPE=DISABLED` | Disabilita completamente le funzioni logiche | N/A |
| Locale | `LOGIC_FUNCTION_TYPE=LOCAL` | Ambienti di sviluppo e attendibili | Basso (nessuna sandbox) |
| Lambda | `LOGIC_FUNCTION_TYPE=LAMBDA` | Produzione con codice non attendibile | Alto (isolamento a livello hardware) |
| Driver | Variabile di ambiente | Caso d'uso | Livello di sicurezza |
| ------------ | -------------------------- | -------------------------------------------- | ------------------------------------ |
| Disabilitato | `SERVERLESS_TYPE=DISABLED` | Disabilita completamente le funzioni logiche | N/A |
| Locale | `SERVERLESS_TYPE=LOCAL` | Ambienti di sviluppo e attendibili | Basso (nessuna sandbox) |
| Lambda | `SERVERLESS_TYPE=LAMBDA` | Produzione con codice non attendibile | Alto (isolamento a livello hardware) |
### Funzioni logiche - Configurazione consigliata
### Configurazione consigliata
**Per lo sviluppo:**
```bash
LOGIC_FUNCTION_TYPE=LOCAL # default when NODE_ENV=development
SERVERLESS_TYPE=LOCAL # default
```
**Per la produzione (AWS):**
```bash
LOGIC_FUNCTION_TYPE=LAMBDA
LOGIC_FUNCTION_LAMBDA_REGION=us-east-1
LOGIC_FUNCTION_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID=your-access-key
LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
SERVERLESS_TYPE=LAMBDA
SERVERLESS_LAMBDA_REGION=us-east-1
SERVERLESS_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
SERVERLESS_LAMBDA_ACCESS_KEY_ID=your-access-key
SERVERLESS_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
```
**Per disabilitare le funzioni logiche:**
```bash
LOGIC_FUNCTION_TYPE=DISABLED # default when NODE_ENV=production
SERVERLESS_TYPE=DISABLED
```
### Interprete del codice - Driver disponibili
| Driver | Variabile di ambiente | Caso d'uso | Livello di sicurezza |
| ------------ | -------------------------------- | ------------------------------------- | ----------------------- |
| Disabilitato | `CODE_INTERPRETER_TYPE=DISABLED` | Disabilita l'esecuzione del codice IA | N/A |
| Locale | `CODE_INTERPRETER_TYPE=LOCAL` | Solo per lo sviluppo | Basso (nessuna sandbox) |
| E2B | `CODE_INTERPRETER_TYPE=E_2_B` | Produzione con esecuzione in sandbox | Alta (sandbox isolata) |
<Note>
Quando si utilizza `LOGIC_FUNCTION_TYPE=DISABLED` o `CODE_INTERPRETER_TYPE=DISABLED`, qualsiasi tentativo di esecuzione restituirà un errore. Ciò è utile se si desidera eseguire Twenty senza queste funzionalità.
Quando si utilizza `SERVERLESS_TYPE=DISABLED`, qualsiasi tentativo di eseguire una funzione logica restituirà un errore. Ciò è utile se si desidera eseguire Twenty senza il supporto per le funzioni logiche.
</Note>
@@ -1,142 +0,0 @@
---
title: Server MCP
description: Collega gli assistenti AI al tuo spazio di lavoro di Twenty utilizzando il Model Context Protocol.
---
<Warning>
MCP è attualmente in **alpha** ed è disponibile solo su alcuni spazi di lavoro. Potrebbe non essere ancora abilitato per il tuo spazio di lavoro.
</Warning>
Twenty espone un server [MCP](https://modelcontextprotocol.io/) affinché gli assistenti AI — Claude Desktop, Claude Code, Cursor, ChatGPT e altri — possano leggere e scrivere i dati del tuo CRM in linguaggio naturale.
Usa l'**URL dello spazio di lavoro** (l'URL che usi per accedere a Twenty) come endpoint MCP. Su Twenty Cloud, l'URL del tuo spazio di lavoro potrebbe essere `https://{mycompany}.twenty.com` oppure un dominio personalizzato. Il server è disponibile all'indirizzo:
| Ambiente | Endpoint MCP |
| ----------------- | ------------------------------------------------------------------------------ |
| **Cloud** | `https://{your-workspace-url}/mcp` (ad es. `https://mycompany.twenty.com/mcp`) |
| **Auto-ospitato** | `https://{your-domain}/mcp` |
## Metodi di autenticazione
Hai due modi per autenticare il tuo client MCP: **OAuth** (consigliato) o **API Key**.
### Opzione A — OAuth (Consigliato)
Con OAuth, il tuo client MCP apre una finestra del browser per effettuare l'accesso. Nessun segreto viene archiviato nei file di configurazione e i token si rinnovano automaticamente.
<Note>
OAuth richiede un client MCP che supporti la [specifica MCP Authorization](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization). Claude Desktop, Claude Code, Cursor e ChatGPT lo supportano.
</Note>
Aggiungi questo alla configurazione del tuo client MCP, sostituendo `{your-workspace-url}` con l'host del tuo spazio di lavoro (ad es. `mycompany.twenty.com`):
```json
{
"mcpServers": {
"twenty": {
"type": "streamable-http",
"url": "https://{your-workspace-url}/mcp"
}
}
}
```
È tutto — non è necessaria alcuna chiave API. Quando il client si connette per la prima volta, eseguirà:
1. Scoprire i metadati OAuth di Twenty tramite `/.well-known/oauth-protected-resource` e `/.well-known/oauth-authorization-server`
2. Registrarsi come client OAuth tramite registrazione dinamica del client (RFC 7591)
3. Aprire il browser per autorizzare l'accesso
4. Ricevere i token e connettersi al server MCP
Le connessioni successive riutilizzano i token memorizzati e li rinnovano automaticamente.
### Opzione B — Chiave API
Se il tuo client MCP non supporta OAuth, o preferisci credenziali statiche, passa una chiave API nell'header `Authorization`:
```json
{
"mcpServers": {
"twenty": {
"type": "streamable-http",
"url": "https://{your-workspace-url}/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
```
<Warning>
La tua chiave API concede l'accesso ai dati dello spazio di lavoro. Mantienila fuori dal controllo versione e dai dotfile condivisi.
</Warning>
Per creare una chiave API, vai su **Impostazioni > API e Webhook > + Crea chiave**. Vedi [API](/l/it/developers/extend/api#create-an-api-key) per i dettagli.
## Avvio rapido
### 1. Copia la configurazione
Vai su **Impostazioni > AI > Altro > MCP Server** in Twenty. Scegli il metodo di autenticazione (OAuth o Chiave API), copia lo snippet JSON (userà già l'URL del tuo spazio di lavoro) e incollalo nel file di configurazione del tuo client MCP.
| Client | Percorso del file di configurazione |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Claude Desktop** | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) o `%APPDATA%\Claude\claude_desktop_config.json` (Windows) |
| **Claude Code** | `~/.claude.json` (utente) o `.mcp.json` (progetto) |
| **Cursor** | `.cursor/mcp.json` nel tuo progetto, oppure `~/.cursor/mcp.json` globalmente |
| **ChatGPT** | Attiva la Modalità sviluppatore in **Impostazioni > App e Connettori > Impostazioni avanzate**, quindi usa **Crea** in **Impostazioni > App e Connettori** per aggiungere il server MCP |
### 2. Connetti
Riavvia il tuo client MCP (o ricarica la configurazione). Se usi OAuth verrai reindirizzato a Twenty per autorizzare l'accesso. Se usi una chiave API la connessione è immediata.
### 3. Inizia a usarlo
Chiedi al tuo assistente AI di interagire con il tuo CRM:
* *"Mostrami le 5 aziende create più di recente"*
* *"Crea una nuova persona di nome Jane Doe presso Acme Corp"*
* *"Trova tutte le opportunità aperte di valore superiore a $10k"*
## Strumenti disponibili
Una volta connesso, il server MCP espone strumenti che rispecchiano l'API di Twenty. Il flusso di lavoro consigliato è:
1. **`get_tool_catalog`** — scoprire tutti gli strumenti disponibili
2. **`learn_tools`** — ottenere lo schema di input per strumenti specifici
3. **`execute_tool`** — eseguire uno strumento
Non è necessario ricordare i nomi degli strumenti. Chiedi al tuo assistente AI cosa può fare e chiamerà `get_tool_catalog` automaticamente.
## Permessi
Le connessioni MCP ereditano le autorizzazioni dell'utente autenticato (OAuth) o il ruolo assegnato alla chiave API. Per limitare ciò che il server MCP può fare:
* **OAuth**: si applica il ruolo dell'utente nello spazio di lavoro.
* **Chiave API**: assegna un ruolo alla chiave API in **Impostazioni > Ruoli**. Vedi [Autorizzazioni](/l/it/user-guide/permissions-access/capabilities/permissions).
## Configurazione self-hosted
Per le istanze self-hosted, sostituisci `{your-workspace-url}` con l'URL del tuo server. Assicurati che `SERVER_URL` nel tuo ambiente corrisponda all'URL pubblico della tua istanza Twenty — viene utilizzato per generare i metadati di discovery OAuth.
```bash
SERVER_URL=https://twenty.yourcompany.com
```
L'endpoint MCP, gli endpoint OAuth e i metadati di discovery derivano tutti da questo valore.
## Risoluzione dei problemi
**Errori "Unauthorized" o 401**
* OAuth: esegui nuovamente l'autorizzazione eliminando i token memorizzati nel tuo client MCP e riconnettiti.
* Chiave API: verifica che la chiave sia valida e non sia scaduta. Rigenerala se necessario.
**Il flusso OAuth non apre il browser**
* Assicurati che il tuo client MCP supporti MCP Authorization. In caso contrario, ricorri al metodo con Chiave API.
**Timeout di connessione**
* Verifica che l'URL dell'endpoint MCP sia raggiungibile dalla tua macchina. Per le istanze self-hosted, controlla che il server sia in esecuzione e che `SERVER_URL` sia impostato correttamente.
@@ -6,7 +6,7 @@ description: O guia para contribuidores (ou desenvolvedores curiosos) que deseja
## Pré-requisitos
<Tabs>
<Tab title="Linux e macOS">
<Tab title="Linux e MacOS">
Antes de instalar e usar o Twenty, certifique-se de instalar o seguinte em seu computador:
* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
@@ -30,7 +30,7 @@ wsl --install
```
Você deve agora ver um aviso para reiniciar o computador. Caso contrário, reinicie-o manualmente.
Ao reiniciar, uma janela do PowerShell será aberta e instalará o Ubuntu. Isso pode levar algum tempo.
Ao reiniciar, uma janela do powershell será aberta e instalará o Ubuntu. Isso pode levar algum tempo.
Você verá uma solicitação para criar um nome de usuário e senha para sua instalação do Ubuntu.
2. Instalar e configurar o git
@@ -102,8 +102,8 @@ Você deve executar todos os comandos nas etapas seguintes a partir da raiz do p
<Tabs>
<Tab title="Linux">
**Opção 1 (preferencial):** Para provisionar seu banco de dados localmente:
Use o seguinte link para instalar o PostgreSQL na sua máquina Linux: [Instalação do PostgreSQL](https://www.postgresql.org/download/linux/)
**Opção 1 (preferencial):** Para prover seu banco de dados localmente:
Use o seguinte link para instalar o Postgresql na sua máquina Linux: [Instalação do Postgresql](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
@@ -130,7 +130,7 @@ Você deve executar todos os comandos nas etapas seguintes a partir da raiz do p
```
O instalador pode não criar o usuário `postgres` por padrão ao instalar
via Homebrew no macOS. Em vez disso, ele cria uma função PostgreSQL que corresponde ao seu nome de usuário do macOS
via Homebrew no MacOS. Em vez disso, ele cria uma função PostgreSQL que corresponde ao seu nome de usuário do macOS
(por exemplo, "john").
Para verificar e criar o usuário `postgres`, se necessário, siga estas etapas:
```bash
@@ -173,8 +173,8 @@ Você deve executar todos os comandos nas etapas seguintes a partir da raiz do p
<Tab title="Windows (WSL)">
Todos os passos a seguir devem ser executados no terminal WSL (dentro da sua máquina virtual)
**Opção 1:** Para provisionar seu PostgreSQL localmente:
Use o seguinte link para instalar o PostgreSQL na sua máquina virtual Linux: [Instalação do PostgreSQL](https://www.postgresql.org/download/linux/)
**Opção 1:** Para provisionar seu Postgresql localmente:
Use o seguinte link para instalar o Postgresql em sua máquina virtual Linux: [Instalação do Postgresql](https://www.postgresql.org/download/linux/)
```bash
psql postgres -c "CREATE DATABASE \"default\";" -c "CREATE DATABASE test;"
```
@@ -189,13 +189,11 @@ Você deve executar todos os comandos nas etapas seguintes a partir da raiz do p
</Tab>
</Tabs>
Agora você pode acessar o banco de dados em `localhost:5432`.
Se você usou a opção do Docker acima, as credenciais padrão são usuário `postgres` e senha `postgres`. Para instalações nativas do PostgreSQL, use as credenciais e os papéis configurados na sua máquina.
Você pode agora acessar o banco de dados em [localhost:5432](localhost:5432), com o usuário `postgres` e senha `postgres`.
## Passo 4: Configurar um Banco de Dados Redis (cache)
O Twenty requer um cache Redis para oferecer o melhor desempenho.
O Twenty requer um cache redis para oferecer o melhor desempenho
<Tabs>
<Tab title="Linux">
@@ -212,10 +210,8 @@ O Twenty requer um cache Redis para oferecer o melhor desempenho.
```bash
brew install redis
```
Inicie o servidor Redis:
```bash
brew services start redis
```
Inicie seu servidor redis:
`brew services start redis`
**Opção 2:** Se você tem o docker instalado:
```bash
@@ -233,11 +229,11 @@ O Twenty requer um cache Redis para oferecer o melhor desempenho.
</Tab>
</Tabs>
Se você precisar de uma GUI de cliente, recomendamos o [Redis Insight](https://redis.io/insight/) (versão gratuita disponível).
Se precisar de uma GUI de Cliente, recomendamos o [redis insight](https://redis.io/insight/) (versão gratuita disponível)
## Passo 5: Configurar variáveis de ambiente
Use variáveis de ambiente ou arquivos `.env` para configurar seu projeto. Mais informações [aqui](/l/pt/developers/self-host/capabilities/setup).
Use variáveis de ambiente ou arquivos `.env` para configurar seu projeto. Mais informações [aqui](/l/pt/developers/self-host/capabilities/setup)
Copie os arquivos `.env.example` em `/front` e `/server`:
@@ -21,51 +21,19 @@ Os aplicativos permitem criar e gerenciar personalizações do Twenty **como có
## Pré-requisitos
* Node.js 24+ e Yarn 4
* Docker (para o servidor de desenvolvimento local do Twenty)
* Um espaço de trabalho do Twenty e uma chave de API (crie uma em https://app.twenty.com/settings/api-webhooks)
## Primeiros passos
Crie um novo app usando o gerador oficial de estrutura. Ele pode iniciar automaticamente uma instância local do Twenty para você:
Crie um novo aplicativo usando o gerador oficial, depois autentique-se e comece a desenvolver:
```bash filename="Terminal"
# Criar a estrutura de um novo app — a CLI oferecerá iniciar um servidor local do Twenty
# Criar a estrutura de um novo app (inclui todos os exemplos por padrão)
npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
# Iniciar modo de desenvolvimento: sincroniza automaticamente as alterações locais com seu workspace
yarn twenty dev
```
### Gerenciamento do Servidor Local
O SDK inclui comandos para gerenciar um servidor de desenvolvimento local do Twenty (imagem Docker all-in-one com PostgreSQL, Redis, servidor e worker):
```bash filename="Terminal"
# Iniciar o servidor local (faz pull da imagem se necessário)
yarn twenty server start
# Verificar o status do servidor
yarn twenty server status
# Transmitir os logs do servidor
yarn twenty server logs
# Parar o servidor
yarn twenty server stop
# Redefinir todos os dados e começar do zero
yarn twenty server reset
```
O servidor local já vem pré-configurado com um espaço de trabalho e um usuário (`tim@apple.dev` / `tim@apple.dev`), para que você possa começar a desenvolver imediatamente, sem qualquer configuração manual.
### Autenticação
Conecte seu aplicativo ao servidor local usando OAuth:
```bash filename="Terminal"
# Authenticate via OAuth (opens browser)
yarn twenty remote add --local
yarn twenty app:dev
```
O gerador de estrutura oferece suporte a dois modos para controlar quais arquivos de exemplo são incluídos:
@@ -81,31 +49,25 @@ npx create-twenty-app@latest my-app --minimal
A partir daqui você pode:
```bash filename="Terminal"
# Adicionar uma nova entidade à sua aplicação (assistido)
# Add a new entity to your application (guided)
yarn twenty entity:add
# Acompanhar os logs das funções da sua aplicação
# Watch your application's function logs
yarn twenty function:logs
# Executar uma função pelo nome
# Execute a function by name
yarn twenty function:execute -n my-function -p '{"name": "test"}'
# Executar a função de pré-instalação
# Execute the pre-install function
yarn twenty function:execute --preInstall
# Executar a função de pós-instalação
# Execute the post-install function
yarn twenty function:execute --postInstall
# Compilar a aplicação para distribuição
yarn twenty app:build
# Publicar a aplicação no npm ou em um servidor Twenty
yarn twenty app:publish
# Desinstalar a aplicação do espaço de trabalho atual
# Uninstall the application from the current workspace
yarn twenty app:uninstall
# Exibir a ajuda dos comandos
# Display commands' help
yarn twenty help
```
@@ -1279,113 +1241,6 @@ Pontos-chave:
Explore um exemplo mínimo de ponta a ponta que demonstra objetos, funções de lógica, componentes de front-end e vários gatilhos [aqui](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/hello-world):
## Compilando seu app
Depois de desenvolver seu app com `app:dev`, use `app:build` para compilá-lo em um pacote distribuível.
```bash filename="Terminal"
# Compilar o app (a saída vai para .twenty/output/)
yarn twenty app:build
# Compilar e criar um tarball (.tgz) para distribuição
yarn twenty app:build --tarball
```
O processo de build:
1. **Analisa e valida o manifesto** — lê todas as entidades `defineX()` dos seus arquivos de código-fonte e valida a estrutura do manifesto.
2. **Compila funções de lógica e componentes de front-end** — empacota o código-fonte TypeScript em arquivos ESM `.mjs` usando o esbuild.
3. **Gera checksums** — calcula hashes MD5 para cada arquivo gerado, armazenados no manifesto como `builtHandlerChecksum` / `builtComponentChecksum`.
4. **Gera o cliente de API tipado** — inspeciona o esquema GraphQL e gera clientes tipados `CoreApiClient` e `MetadataApiClient`.
5. **Executa uma verificação de tipos do TypeScript** — executa `tsc --noEmit` para detectar erros de tipo antes da publicação.
6. **Reconstrói com o cliente gerado** — realiza uma segunda passagem de compilação para que os tipos do cliente gerado sejam incluídos.
7. **Opcionalmente cria um tarball** — se `--tarball` for passado, executa `npm pack` para criar um arquivo `.tgz` pronto para distribuição.
A saída da compilação em `.twenty/output/` contém:
```text
.twenty/output/
├── manifest.json # Manifesto com somas de verificação para todos os arquivos compilados
├── package.json # Copiado da raiz do aplicativo
├── yarn.lock # Copiado da raiz do aplicativo
├── src/
│ ├── logic-functions/ # Arquivos .mjs compilados de funções de lógica
│ └── front-components/ # Arquivos .mjs compilados de componentes de front-end
├── public/ # Recursos estáticos (se houver)
└── my-app-1.0.0.tgz # Apenas com a opção --tarball
```
| Opção | Descrição |
| ----------- | --------------------------------------------------------- |
| `[appPath]` | Caminho para o diretório do app (padrão: diretório atual) |
| `--tarball` | Também empacota a saída em um tarball `.tgz` |
## Publicando seu app
Use `app:publish` para distribuir seu app — ou para o registro do npm ou diretamente para um servidor Twenty.
### Publicar no npm (padrão)
```bash filename="Terminal"
# Publish to npm (requires npm login)
yarn twenty app:publish
# Publish with a dist-tag (e.g. beta, next)
yarn twenty app:publish --tag beta
```
Isso compila o app e executa `npm publish` a partir do diretório `.twenty/output/`. O pacote publicado pode então ser instalado no marketplace da Twenty por qualquer espaço de trabalho.
### Publicar em um servidor Twenty
```bash filename="Terminal"
# Publish directly to a Twenty server
yarn twenty app:publish --server https://app.twenty.com
```
Isso compila o app com um tarball, faz o upload para o servidor via a mutação GraphQL `uploadAppTarball` e aciona a instalação em uma única etapa. Isso é útil para implantações privadas ou para testar em um servidor específico.
| Opção | Descrição |
| ----------------- | --------------------------------------------------------------------- |
| `[appPath]` | Caminho para o diretório do app (padrão: diretório atual) |
| `--server <url>` | Publicar em um servidor Twenty em vez de no npm |
| `--token <token>` | Token de autenticação para o servidor de destino |
| `--tag <tag>` | dist-tag do npm (ex.: `beta`, `next`) — apenas para publicação no npm |
## Registro de aplicação
Antes que um app possa ser instalado em um espaço de trabalho, ele precisa ser **registrado**. Um registro é um registro de metadados que descreve de onde o app vem e como autenticá-lo. Isso é tratado automaticamente pela CLI na maioria dos casos.
### Tipos de origem
Cada registro tem um **tipo de origem** que determina como os arquivos do app são resolvidos durante a instalação:
| Tipo de origem | Como os arquivos são resolvidos | Caso de uso típico |
| -------------- | ------------------------------------------------------------------------------------------- | --------------------------------------- |
| `LOCAL` | Os arquivos são sincronizados em tempo real pelo observador da CLI — a instalação é omitida | Desenvolvimento com `app:dev` |
| `NPM` | Obtidos do registro npm por meio do campo `sourcePackage` | Apps publicados no npm |
| `TARBALL` | Extraídos de um arquivo `.tgz` enviado e armazenado no servidor | Apps privados publicados com `--server` |
### Como o registro acontece
* **`app:dev`** — cria automaticamente um registro `LOCAL` na primeira vez que você executa o modo de desenvolvimento em um espaço de trabalho.
* **`app:publish --server`** — faz o upload de um tarball e cria (ou atualiza) um registro `TARBALL`, e em seguida instala o app.
* **marketplace do npm** — registros `NPM` são criados quando apps são sincronizados do registro npm para o catálogo do marketplace da Twenty.
* **API GraphQL** — você também pode criar registros programaticamente por meio da mutação `createApplicationRegistration`.
### Registro vs instalação
**Registro** e **instalação** são conceitos distintos:
* Um **registro** (`ApplicationRegistration`) é um registro global de metadados que descreve o app: seu nome, tipo de origem, credenciais OAuth e status de listagem no marketplace. Ele existe independentemente de qualquer espaço de trabalho.
* Uma **instalação** (`Application`) é uma instância por espaço de trabalho. Quando um usuário instala um app, a Twenty resolve o pacote a partir da origem do registro, grava os arquivos compilados no armazenamento e sincroniza o manifesto (criando objetos, campos, funções de lógica etc.). naquele espaço de trabalho.
Um registro pode ser instalado em muitos espaços de trabalho. Cada espaço de trabalho recebe sua própria cópia dos arquivos e do modelo de dados do app.
### Credenciais OAuth
Cada registro inclui credenciais OAuth (`oAuthClientId` e `oAuthClientSecret`) geradas no momento da criação. Elas são usadas pelo app para autenticar requisições de API em nome dos usuários. O segredo do cliente é retornado **uma única vez** na criação — armazene-o com segurança. Você pode rotacioná-lo posteriormente por meio da mutação `rotateApplicationRegistrationClientSecret`.
## Configuração manual (sem o gerador)
Embora recomendemos usar `create-twenty-app` para a melhor experiência inicial, você também pode configurar um projeto manualmente. Não instale a CLI globalmente. Em vez disso, adicione `twenty-sdk` como uma dependência local e configure um único script no seu package.json:
@@ -3,7 +3,7 @@ title: 1-Clique c/ Docker Compose
---
<Warning>
Os contêineres Docker são para hospedagem em produção ou auto-hospedagem. Para contribuir, consulte a [Configuração local](/l/pt/developers/contribute/capabilities/local-setup).
Contêineres Docker são para hospedagem de produção ou auto-hospedagem, para contribuições, por favor, verifique o [Setup Local](/l/pt/developers/contribute/capabilities/local-setup).
</Warning>
## Visão geral
@@ -12,7 +12,7 @@ Este guia fornece instruções passo a passo para instalar e configurar o aplica
**Importante:** Modifique apenas as configurações explicitamente mencionadas neste guia. Alterar outras configurações pode levar a problemas.
Consulte [Configurar Variáveis de Ambiente](/l/pt/developers/self-host/capabilities/setup) para configuração avançada. Todas as variáveis de ambiente devem ser declaradas no arquivo `docker-compose.yml` no nível do servidor e/ou do trabalhador, dependendo da variável.
Veja a documentação [Configurar Variáveis de Ambiente](/l/pt/developers/self-host/capabilities/setup) para configuração avançada. Todas as variáveis de ambiente devem ser declaradas no arquivo docker-compose.yml no nível do servidor e/ou trabalhador, dependendo da variável.
## Requisitos do Sistema
@@ -297,60 +297,46 @@ yarn command:prod cron:workflow:automated-cron-trigger
**Modo somente ambiente:** Se você definir `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false`, adicione estas variáveis ao seu arquivo `.env`.
</Warning>
## Funções lógicas e interpretador de código
## Funções lógicas
O Twenty oferece suporte a funções lógicas para fluxos de trabalho e ao interpretador de código para análise de dados com IA. Ambos executam código fornecido pelo usuário e exigem configuração explícita por motivos de segurança.
### Padrões de segurança
**Em produção (NODE_ENV=production):** Tanto as funções lógicas quanto o interpretador de código têm como padrão **Desativado**. Você deve habilitá-los explicitamente com `LOGIC_FUNCTION_TYPE` e `CODE_INTERPRETER_TYPE` se precisar desses recursos.
**Em desenvolvimento (NODE_ENV=development):** Ambos têm como padrão **LOCAL** por conveniência ao executar localmente.
O Twenty oferece suporte a funções lógicas para fluxos de trabalho e lógica personalizada. O ambiente de execução é configurado por meio da variável de ambiente `SERVERLESS_TYPE`.
<Warning>
**Aviso de segurança:** O driver local (`LOGIC_FUNCTION_TYPE=LOCAL` ou `CODE_INTERPRETER_TYPE=LOCAL`) executa código diretamente no host em um processo Node.js sem sandbox. Deve ser usado apenas para código confiável em desenvolvimento. Para implantações de produção que lidam com código não confiável, use `LOGIC_FUNCTION_TYPE=LAMBDA` ou `CODE_INTERPRETER_TYPE=E2B` (com sandbox), ou mantenha-os desativados.
**Aviso de segurança:** O driver local (`SERVERLESS_TYPE=LOCAL`) executa código diretamente no host em um processo Node.js sem sandbox. Deve ser usado apenas para código confiável em desenvolvimento. Para implantações de produção que lidam com código não confiável, recomendamos fortemente usar `SERVERLESS_TYPE=LAMBDA` ou `SERVERLESS_TYPE=DISABLED`.
</Warning>
### Funções lógicas - Drivers disponíveis
### Drivers disponíveis
| Driver | Variável de ambiente | Caso de uso | Nível de segurança |
| ---------- | ------------------------------ | ------------------------------------------ | -------------------------------------- |
| Desativado | `LOGIC_FUNCTION_TYPE=DISABLED` | Desativar completamente as funções lógicas | N/A |
| Local | `LOGIC_FUNCTION_TYPE=LOCAL` | Desenvolvimento e ambientes confiáveis | Baixo (sem sandbox) |
| Lambda | `LOGIC_FUNCTION_TYPE=LAMBDA` | Produção com código não confiável | Alto (isolamento em nível de hardware) |
| Driver | Variável de ambiente | Caso de uso | Nível de segurança |
| ---------- | -------------------------- | ------------------------------------------ | -------------------------------------- |
| Desativado | `SERVERLESS_TYPE=DISABLED` | Desativar completamente as funções lógicas | N/A |
| Local | `SERVERLESS_TYPE=LOCAL` | Desenvolvimento e ambientes confiáveis | Baixo (sem sandbox) |
| Lambda | `SERVERLESS_TYPE=LAMBDA` | Produção com código não confiável | Alto (isolamento em nível de hardware) |
### Funções lógicas - Configuração recomendada
### Configuração recomendada
**Para desenvolvimento:**
```bash
LOGIC_FUNCTION_TYPE=LOCAL # default when NODE_ENV=development
SERVERLESS_TYPE=LOCAL # default
```
**Para produção (AWS):**
```bash
LOGIC_FUNCTION_TYPE=LAMBDA
LOGIC_FUNCTION_LAMBDA_REGION=us-east-1
LOGIC_FUNCTION_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID=your-access-key
LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
SERVERLESS_TYPE=LAMBDA
SERVERLESS_LAMBDA_REGION=us-east-1
SERVERLESS_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
SERVERLESS_LAMBDA_ACCESS_KEY_ID=your-access-key
SERVERLESS_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
```
**Para desativar as funções lógicas:**
```bash
LOGIC_FUNCTION_TYPE=DISABLED # default when NODE_ENV=production
SERVERLESS_TYPE=DISABLED
```
### Interpretador de código - Drivers disponíveis
| Driver | Variável de ambiente | Caso de uso | Nível de segurança |
| ---------- | -------------------------------- | ------------------------------------ | ---------------------- |
| Desativado | `CODE_INTERPRETER_TYPE=DISABLED` | Desativar a execução de código de IA | N/A |
| Local | `CODE_INTERPRETER_TYPE=LOCAL` | Apenas para desenvolvimento | Baixo (sem sandbox) |
| E2B | `CODE_INTERPRETER_TYPE=E_2_B` | Produção com execução em sandbox | Alto (sandbox isolado) |
<Note>
Ao usar `LOGIC_FUNCTION_TYPE=DISABLED` ou `CODE_INTERPRETER_TYPE=DISABLED`, qualquer tentativa de execução retornará um erro. Isso é útil se você quiser executar o Twenty sem esses recursos.
Ao usar `SERVERLESS_TYPE=DISABLED`, qualquer tentativa de executar uma função lógica retornará um erro. Isso é útil se você quiser executar o Twenty sem recursos de funções lógicas.
</Note>
@@ -1,142 +0,0 @@
---
title: Servidor MCP
description: Conecte assistentes de IA ao seu espaço de trabalho do Twenty usando o Model Context Protocol.
---
<Warning>
O MCP está atualmente em **alfa** e está disponível apenas em alguns espaços de trabalho. O MCP pode ainda não estar ativado no seu espaço de trabalho.
</Warning>
O Twenty expõe um servidor [MCP](https://modelcontextprotocol.io/) para que assistentes de IA — Claude Desktop, Claude Code, Cursor, ChatGPT e outros — possam ler e escrever seus dados de CRM por meio de linguagem natural.
Use o **URL do espaço de trabalho** (o URL que você usa para acessar o Twenty) como o endpoint do MCP. Na Twenty Cloud, o URL do seu espaço de trabalho pode ser `https://{mycompany}.twenty.com` ou um domínio personalizado. O servidor está disponível em:
| Ambiente | Endpoint do MCP |
| ------------------ | ------------------------------------------------------------------------------------ |
| **Nuvem** | `https://{your-workspace-url}/mcp` (por exemplo, `https://mycompany.twenty.com/mcp`) |
| **Auto-hospedado** | `https://{your-domain}/mcp` |
## Métodos de autenticação
Você tem duas maneiras de autenticar seu cliente MCP: **OAuth** (recomendado) ou **Chave de API**.
### Opção A — OAuth (recomendado)
Com o OAuth, seu cliente MCP abre uma janela do navegador para você fazer login. Nenhum segredo é armazenado em arquivos de configuração, e os tokens são atualizados automaticamente.
<Note>
O OAuth requer um cliente MCP que ofereça suporte à [especificação de Autorização MCP](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization). Claude Desktop, Claude Code, Cursor e ChatGPT oferecem suporte.
</Note>
Adicione isto à configuração do seu cliente MCP, substituindo `{your-workspace-url}` pelo host do seu espaço de trabalho (por exemplo, `mycompany.twenty.com`):
```json
{
"mcpServers": {
"twenty": {
"type": "streamable-http",
"url": "https://{your-workspace-url}/mcp"
}
}
}
```
É isso — nenhuma chave de API é necessária. Quando o cliente se conectar pela primeira vez, ele irá:
1. Descobrir os metadados de OAuth do Twenty por meio de `/.well-known/oauth-protected-resource` e `/.well-known/oauth-authorization-server`
2. Registrar-se como um cliente OAuth por meio de registro dinâmico de cliente (RFC 7591)
3. Abrir seu navegador para autorizar o acesso
4. Receber tokens e conectar-se ao servidor MCP
Conexões subsequentes reutilizam os tokens armazenados e os atualizam automaticamente.
### Opção B — Chave de API
Se o seu cliente MCP não oferecer suporte a OAuth, ou se você preferir credenciais estáticas, passe uma chave de API no cabeçalho `Authorization`:
```json
{
"mcpServers": {
"twenty": {
"type": "streamable-http",
"url": "https://{your-workspace-url}/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
```
<Warning>
Sua chave de API concede acesso aos dados do espaço de trabalho. Mantenha-a fora do controle de versão e de dotfiles compartilhados.
</Warning>
Para criar uma chave de API, vá em **Settings > APIs & Webhooks > + Create key**. Veja [APIs](/l/pt/developers/extend/api#create-an-api-key) para detalhes.
## Início rápido
### 1. Copie a configuração
Vá até **Settings > AI > More > MCP Server** no Twenty. Escolha seu método de autenticação (OAuth ou Chave de API), copie o trecho de JSON (ele já usará o URL do seu espaço de trabalho) e cole-o no arquivo de configuração do seu cliente MCP.
| Cliente | Local do arquivo de configuração |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Claude Desktop** | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) ou `%APPDATA%\Claude\claude_desktop_config.json` (Windows) |
| **Claude Code** | `~/.claude.json` (usuário) ou `.mcp.json` (projeto) |
| **Cursor** | `.cursor/mcp.json` no seu projeto, ou `~/.cursor/mcp.json` globalmente |
| **ChatGPT** | Ative o Modo Desenvolvedor em **Settings > Apps & Connectors > Advanced settings** e, em seguida, use **Create** em **Settings > Apps & Connectors** para adicionar o servidor MCP |
### 2. Conectar
Reinicie seu cliente MCP (ou recarregue a configuração). Se estiver usando OAuth, você será redirecionado ao Twenty para autorizar o acesso. Se estiver usando uma chave de API, a conexão é imediata.
### 3. Comece a usá-lo
Peça ao seu assistente de IA para interagir com seu CRM:
* *"Mostre-me as 5 empresas criadas mais recentemente"*
* *"Crie uma nova pessoa chamada Jane Doe na Acme Corp"*
* *"Encontre todas as oportunidades em aberto com valor superior a $10k"*
## Ferramentas disponíveis
Depois de conectado, o servidor MCP expõe ferramentas que refletem a API do Twenty. O fluxo de trabalho recomendado é:
1. **`get_tool_catalog`** — descobrir todas as ferramentas disponíveis
2. **`learn_tools`** — obter o esquema de entrada para ferramentas específicas
3. **`execute_tool`** — executar uma ferramenta
Você não precisa se lembrar dos nomes das ferramentas. Pergunte ao seu assistente de IA o que ele pode fazer e ele chamará `get_tool_catalog` automaticamente.
## Permissões
As conexões MCP herdam as permissões do usuário autenticado (OAuth) ou da função atribuída à chave de API. Para restringir o que o servidor MCP pode fazer:
* **OAuth**: Aplica-se à função do espaço de trabalho do usuário.
* **Chave de API**: Atribua uma função à chave de API em **Settings > Roles**. Veja [Permissões](/l/pt/user-guide/permissions-access/capabilities/permissions).
## Configuração auto-hospedada
Para instâncias auto-hospedadas, substitua `{your-workspace-url}` pelo URL do seu servidor. Certifique-se de que `SERVER_URL` no seu ambiente corresponda ao URL público da sua instância do Twenty — isso é usado para gerar os metadados de descoberta do OAuth.
```bash
SERVER_URL=https://twenty.yourcompany.com
```
O endpoint do MCP, os endpoints de OAuth e os metadados de descoberta derivam todos desse valor.
## Resolução de Problemas
**Erros "Unauthorized" ou 401**
* OAuth: autorize novamente limpando os tokens armazenados no seu cliente MCP e reconectando.
* Chave de API: verifique se a chave é válida e não expirou. Gere-a novamente, se necessário.
**O fluxo do OAuth não abre um navegador**
* Garanta que seu cliente MCP ofereça suporte à Autorização MCP. Se não oferecer, utilize o método de Chave de API.
**Tempo limite de conexão**
* Confirme que o URL do endpoint MCP é acessível a partir da sua máquina. Para instâncias auto-hospedadas, verifique se o servidor está em execução e se `SERVER_URL` está definido corretamente.
@@ -6,7 +6,7 @@ description: Ghidul pentru contribuitori (sau dezvoltatori curioși) care doresc
## Cerințe
<Tabs>
<Tab title="Linux și macOS">
<Tab title="Linux și MacOS">
Înainte de a instala și utiliza Twenty, asigurați-vă că instalați următoarele pe computerul dvs.:
* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
@@ -129,8 +129,8 @@ Trebuie să rulați toate comenzile în pașii următori de la rădăcina proiec
brew services list
```
Instalatorul s-ar putea să nu creeze implicit utilizatorul `postgres` la instalarea
prin Homebrew pe macOS. În schimb, creează un rol PostgreSQL care se potrivește cu numele de utilizator al
Instalatorul s-ar putea să nu creeze implicit utilizatorul `postgres` atunci când instalați
prin Homebrew pe MacOS. În schimb, creează un rol PostgreSQL care se potrivește cu numele de utilizator al
macOS-ului dvs. (de ex., "john").
Pentru a verifica și crea utilizatorul `postgres` dacă este necesar, urmați acești pași:
```bash
@@ -189,13 +189,11 @@ Trebuie să rulați toate comenzile în pașii următori de la rădăcina proiec
</Tab>
</Tabs>
Acum puteți accesa baza de date la `localhost:5432`.
Dacă ați folosit opțiunea Docker de mai sus, datele implicite de autentificare sunt utilizatorul `postgres` și parola `postgres`. Pentru instalările native PostgreSQL, folosiți datele de autentificare și rolurile configurate pe mașina dvs.
Acum puteți accesa baza de date la [localhost:5432](localhost:5432), cu utilizator `postgres` și parolă `postgres`.
## Pasul 4: Configurați o bază de date Redis (cache)
Twenty necesită un cache Redis pentru a oferi cea mai bună performanță.
Twenty necesită un cache Redis pentru a oferi cea mai bună performanță
<Tabs>
<Tab title="Linux">
@@ -213,9 +211,7 @@ Twenty necesită un cache Redis pentru a oferi cea mai bună performanță.
brew install redis
```
Porniți serverul Redis:
```bash
brew services start redis
```
`brew services start redis`
**Opțiunea 2:** Dacă aveți docker instalat:
```bash
@@ -233,11 +229,11 @@ Twenty necesită un cache Redis pentru a oferi cea mai bună performanță.
</Tab>
</Tabs>
Dacă aveți nevoie de o interfață grafică pentru client, vă recomandăm [Redis Insight](https://redis.io/insight/) (versiune gratuită disponibilă).
Dacă aveți nevoie de o interfață grafică pentru client, vă recomandăm [Redis Insight](https://redis.io/insight/) (versiune gratuită disponibilă)
## Pasul 5: Configurați variabilele de mediu
Utilizați variabile de mediu sau fișiere `.env` pentru a configura proiectul dvs. Mai multe informații [aici](/l/ro/developers/self-host/capabilities/setup).
Utilizați variabile de mediu sau fișiere `.env` pentru a configura proiectul dvs. Mai multe informații [aici](/l/ro/developers/self-host/capabilities/setup)
Copiați fișierele `.env.example` din `/front` și `/server`:
@@ -21,51 +21,19 @@ Aplicațiile vă permit să construiți și să gestionați personalizările Twe
## Cerințe
* Node.js 24+ și Yarn 4
* Docker (pentru serverul local de dezvoltare Twenty)
* Un spațiu de lucru Twenty și o cheie API (creați una la https://app.twenty.com/settings/api-webhooks)
## Începeți
Creează o aplicație nouă folosind generatorul oficial. Poate porni automat o instanță Twenty locală pentru tine:
Creați o aplicație nouă folosind generatorul oficial, apoi autentificați-vă și începeți să dezvoltați:
```bash filename="Terminal"
# Creează scheletul unei aplicații noi — CLI-ul îți va oferi opțiunea de a porni un server Twenty local
# Creează scheletul unei aplicații noi (include toate exemplele în mod implicit)
npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
# Pornește modul de dezvoltare: sincronizează automat modificările locale cu spațiul tău de lucru
yarn twenty dev
```
### Gestionarea serverului local
SDK-ul include comenzi pentru a gestiona un server local de dezvoltare Twenty (imagine Docker all-in-one cu PostgreSQL, Redis, server și worker):
```bash filename="Terminal"
# Pornește serverul local (descarcă imaginea dacă este necesar)
yarn twenty server start
# Verifică starea serverului
yarn twenty server status
# Afișează în timp real jurnalele serverului
yarn twenty server logs
# Oprește serverul
yarn twenty server stop
# Resetează toate datele și pornește de la zero
yarn twenty server reset
```
Serverul local vine preconfigurat cu un spațiu de lucru și un utilizator (`tim@apple.dev` / `tim@apple.dev`), astfel încât să poți începe să dezvolți imediat, fără nicio configurare manuală.
### Autentificare
Conectează-ți aplicația la serverul local folosind OAuth:
```bash filename="Terminal"
# Autentifică-te prin OAuth (se deschide browserul)
yarn twenty remote add --local
yarn twenty app:dev
```
Generatorul de schelet acceptă două moduri pentru a controla ce fișiere de exemplu sunt incluse:
@@ -81,32 +49,26 @@ npx create-twenty-app@latest my-app --minimal
De aici puteți:
```bash filename="Terminal"
# Add a new entity to your application (guided)
# Adaugă o entitate nouă în aplicația ta (ghidat)
yarn twenty entity:add
# Watch your application's function logs
# Urmărește jurnalele funcțiilor aplicației tale
yarn twenty function:logs
# Execute a function by name
# Execută o funcție după nume
yarn twenty function:execute -n my-function -p '{"name": "test"}'
# Execute the pre-install function
# Execută funcția de pre-instalare
yarn twenty function:execute --preInstall
# Execute the post-install function
# Execută funcția post-instalare
yarn twenty function:execute --postInstall
# Build the app for distribution
yarn twenty app:build
# Publish the app to npm or a Twenty server
yarn twenty app:publish
# Uninstall the application from the current workspace
# Dezinstalează aplicația din spațiul de lucru curent
yarn twenty app:uninstall
# Display commands' help
yarn twenty help
# Afișează ajutorul pentru comenzi
yarn twenty help},{
```
Consultați și: paginile de referință CLI pentru [create-twenty-app](https://www.npmjs.com/package/create-twenty-app) și [twenty-sdk CLI](https://www.npmjs.com/package/twenty-sdk).
@@ -1278,113 +1240,6 @@ Puncte cheie:
Explorați un exemplu minim, cap la cap, care demonstrează obiecte, funcții de logică, componente Front și declanșatoare multiple [aici](https://github.com/twentyhq/twenty/tree/main/packages/twenty-apps/hello-world):
## Building your app
Once you've developed your app with `app:dev`, use `app:build` to compile it into a distributable package.
```bash filename="Terminal"
# Build the app (output goes to .twenty/output/)
yarn twenty app:build
# Build and create a tarball (.tgz) for distribution
yarn twenty app:build --tarball
```
The build process:
1. **Parses and validates the manifest** — reads all `defineX()` entities from your source files and validates the manifest structure.
2. **Compiles logic functions and front components** — bundles TypeScript sources into ESM `.mjs` files using esbuild.
3. **Generates checksums** — computes MD5 hashes for each built file, stored in the manifest as `builtHandlerChecksum` / `builtComponentChecksum`.
4. **Generează clientul API tipizat** — examinează schema GraphQL și generează clienți tipizați `CoreApiClient` și `MetadataApiClient`.
5. **Rulează o verificare a tipurilor TypeScript** — rulează `tsc --noEmit` pentru a detecta erorile de tip înainte de publicare.
6. **Reconstruiește cu clientul generat** — efectuează o a doua trecere de compilare astfel încât tipurile clientului generat să fie incluse.
7. **Creează opțional un tarball** — dacă se trece `--tarball`, rulează `npm pack` pentru a crea un fișier `.tgz` gata pentru distribuire.
Rezultatul build-ului din `.twenty/output/` conține:
```text
.twenty/output/
├── manifest.json # Manifest cu sume de control pentru toate fișierele generate
├── package.json # Copiat din rădăcina aplicației
├── yarn.lock # Copiat din rădăcina aplicației
├── src/
│ ├── logic-functions/ # Fișiere .mjs de funcții de logică compilate
│ └── front-components/ # Fișiere .mjs de componente front-end compilate
├── public/ # Resurse statice (dacă există)
└── my-app-1.0.0.tgz # Doar cu opțiunea --tarball
```
| Opțiune | Descriere |
| ----------- | -------------------------------------------------------------- |
| `[appPath]` | Calea către directorul aplicației (implicit directorul curent) |
| `--tarball` | De asemenea, împachetează rezultatul într-un tarball `.tgz` |
## Publicarea aplicației
Folosește `app:publish` pentru a distribui aplicația — fie în registrul npm, fie direct pe un server Twenty.
### Publicare pe npm (implicit)
```bash filename="Terminal"
# Publicare pe npm (necesită autentificare npm)
yarn twenty app:publish
# Publicare cu un dist-tag (de ex. beta, next)
yarn twenty app:publish --tag beta
```
Aceasta construiește aplicația și rulează `npm publish` din directorul `.twenty/output/`. Pachetul publicat poate fi apoi instalat din marketplace-ul Twenty de către orice spațiu de lucru.
### Publicare pe un server Twenty
```bash filename="Terminal"
# Publicare direct pe un server Twenty
yarn twenty app:publish --server https://app.twenty.com
```
Aceasta construiește aplicația cu un tarball, o încarcă pe server prin mutația GraphQL `uploadAppTarball` și declanșează instalarea într-un singur pas. Acest lucru este util pentru implementări private sau pentru testare pe un server specific.
| Opțiune | Descriere |
| ----------------- | -------------------------------------------------------------------- |
| `[appPath]` | Calea către directorul aplicației (implicit directorul curent) |
| `--server <url>` | Publică pe un server Twenty în loc de npm |
| `--token <token>` | Jeton de autentificare pentru serverul țintă |
| `--tag <tag>` | npm dist-tag (de ex. `beta`, `next`) — doar pentru publicarea pe npm |
## Înregistrarea aplicației
Înainte ca o aplicație să poată fi instalată într-un spațiu de lucru, aceasta trebuie să fie **înregistrată**. O înregistrare este o înregistrare de metadate care descrie de unde provine aplicația și cum se autentifică. Acest lucru este gestionat automat de CLI în cele mai multe cazuri.
### Tipuri de sursă
Fiecare înregistrare are un **tip de sursă** care determină modul în care fișierele aplicației sunt preluate în timpul instalării:
| Tip de sursă | Cum sunt preluate fișierele | Caz de utilizare tipic |
| ------------ | ---------------------------------------------------------------------------------------- | ----------------------------------------- |
| `LOCAL` | Fișierele sunt sincronizate în timp real de către watcher-ul CLI — instalarea este omisă | Dezvoltare cu `app:dev` |
| `NPM` | Obținute din registrul npm prin câmpul `sourcePackage` | Aplicații publicate pe npm |
| `TARBALL` | Extrase dintr-un fișier `.tgz` încărcat, stocat pe server | Aplicații private publicate cu `--server` |
### Cum are loc înregistrarea
* **`app:dev`** — creează automat o înregistrare `LOCAL` prima dată când rulezi modul de dezvoltare pentru un spațiu de lucru.
* **`app:publish --server`** — încarcă un tarball și creează (sau actualizează) o înregistrare `TARBALL`, apoi instalează aplicația.
* **marketplace-ul npm** — înregistrările `NPM` sunt create când aplicațiile sunt sincronizate din registrul npm în catalogul marketplace-ului Twenty.
* **API GraphQL** — poți de asemenea să creezi înregistrări programatic prin mutația `createApplicationRegistration`.
### Înregistrare vs instalare
**Înregistrarea** și **instalarea** sunt concepte separate:
* O **înregistrare** (`ApplicationRegistration`) este o înregistrare globală de metadate care descrie aplicația: numele ei, tipul de sursă, acreditările OAuth și statutul listării în marketplace. Există independent de orice spațiu de lucru.
* O **instalare** (`Application`) este o instanță per spațiu de lucru. Când un utilizator instalează o aplicație, Twenty rezolvă pachetul din sursa înregistrării, scrie fișierele compilate în stocare și sincronizează manifestul (creând obiecte, câmpuri, funcții de logică etc.) în acel spațiu de lucru.
O singură înregistrare poate fi instalată în multe spații de lucru. Fiecare spațiu de lucru primește propria copie a fișierelor și a modelului de date al aplicației.
### Acreditări OAuth
Fiecare înregistrare include acreditări OAuth (`oAuthClientId` și `oAuthClientSecret`) generate la momentul creării. Acestea sunt folosite de aplicație pentru a autentifica cererile API în numele utilizatorilor. Secretul clientului este returnat **o singură dată** la creare — păstrează-l în siguranță. Îl poți roti ulterior prin mutația `rotateApplicationRegistrationClientSecret`.
## Configurare manuală (fără generator)
Deși recomandăm utilizarea `create-twenty-app` pentru cea mai bună experiență de început, puteți configura și un proiect manual. Nu instalați CLI-ul global. În schimb, adăugați `twenty-sdk` ca dependență locală și conectați un singur script în package.json-ul dvs.:
@@ -3,7 +3,7 @@ title: 1-Click cu Docker Compose
---
<Warning>
Containerele Docker sunt destinate găzduirii în producție sau auto-găzduirii. Pentru a contribui, consultați [Configurarea locală](/l/ro/developers/contribute/capabilities/local-setup).
Containerele Docker sunt pentru găzduire în producție sau auto-găzduire; pentru a contribui, consultați [Configurare locală](/l/ro/developers/contribute/capabilities/local-setup).
</Warning>
## Prezentare generală
@@ -12,7 +12,7 @@ Acest ghid oferă instrucțiuni pas cu pas pentru a instala și configura aplica
**Important:** Modificați numai setările menționate explicit în acest ghid. Modificarea altor configurații poate duce la probleme.
Consultați [Setup Environment Variables](/l/ro/developers/self-host/capabilities/setup) pentru configurare avansată. Toate variabilele de mediu trebuie declarate în fișierul `docker-compose.yml` la nivel de server și/sau de lucru, în funcție de variabilă.
Consultați documentația [Setup Environment Variables](/l/ro/developers/self-host/capabilities/setup) pentru configurare avansată. Toate variabilele de mediu trebuie declarate în fișierul docker-compose.yml la nivel de server și/sau de lucru, în funcție de variabilă.
## Cerințe de Sistem
@@ -297,60 +297,46 @@ yarn command:prod cron:workflow:automated-cron-trigger
**Mod doar pentru mediu:** Dacă setați `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false`, adăugați aceste variabile în fișierul dvs. `.env` în schimb.
</Warning>
## Funcții logice și interpretor de cod
## Funcții logice
Twenty acceptă funcții logice pentru fluxuri de lucru și interpretorul de cod pentru analiza datelor cu AI. Ambele rulează cod furnizat de utilizator și necesită o configurare explicită din motive de securitate.
### Valori implicite de securitate
**În producție (NODE_ENV=production):** Atât funcțiile logice, cât și interpretorul de cod au implicit valoarea **Dezactivat**. Trebuie să le activezi explicit cu `LOGIC_FUNCTION_TYPE` și `CODE_INTERPRETER_TYPE` dacă ai nevoie de aceste funcționalități.
**În dezvoltare (NODE_ENV=development):** Ambele au implicit valoarea **LOCAL** pentru comoditate când rulezi local.
Twenty acceptă funcții logice pentru fluxuri de lucru și logică personalizată. Mediul de execuție este configurat prin variabila de mediu `SERVERLESS_TYPE`.
<Warning>
**Atenționare de securitate:** Driverul local (`LOGIC_FUNCTION_TYPE=LOCAL` sau `CODE_INTERPRETER_TYPE=LOCAL`) rulează codul direct pe gazdă într-un proces Node.js, fără sandboxing. Ar trebui utilizat doar pentru cod de încredere, în dezvoltare. Pentru implementări în producție care gestionează cod neverificat, folosiți `LOGIC_FUNCTION_TYPE=LAMBDA` sau `CODE_INTERPRETER_TYPE=E2B` (cu sandboxing) ori păstrați-le dezactivate.
**Atenționare de securitate:** Driverul local (`SERVERLESS_TYPE=LOCAL`) rulează codul direct pe gazdă într-un proces Node.js, fără sandboxing. Ar trebui utilizat doar pentru cod de încredere, în dezvoltare. Pentru implementări de producție care gestionează cod neverificat, recomandăm cu tărie utilizarea `SERVERLESS_TYPE=LAMBDA` sau `SERVERLESS_TYPE=DISABLED`.
</Warning>
### Funcții logice - Drivere disponibile
### Drivere disponibile
| Driver | Variabilă de mediu | Caz de utilizare | Nivel de securitate |
| ---------- | ------------------------------ | ------------------------------------- | -------------------------------------- |
| Dezactivat | `LOGIC_FUNCTION_TYPE=DISABLED` | Dezactivează complet funcțiile logice | N/A |
| Local | `LOGIC_FUNCTION_TYPE=LOCAL` | Dezvoltare și medii de încredere | Scăzut (fără sandboxing) |
| Lambda | `LOGIC_FUNCTION_TYPE=LAMBDA` | Producție cu cod neverificat | Ridicat (izolare la nivel de hardware) |
| Driver | Variabilă de mediu | Caz de utilizare | Nivel de securitate |
| ---------- | -------------------------- | ------------------------------------- | -------------------------------------- |
| Dezactivat | `SERVERLESS_TYPE=DISABLED` | Dezactivează complet funcțiile logice | N/A |
| Local | `SERVERLESS_TYPE=LOCAL` | Dezvoltare și medii de încredere | Scăzut (fără sandboxing) |
| Lambda | `SERVERLESS_TYPE=LAMBDA` | Producție cu cod neverificat | Ridicat (izolare la nivel de hardware) |
### Funcții logice - Configurare recomandată
### Configurație recomandată
**Pentru dezvoltare:**
```bash
LOGIC_FUNCTION_TYPE=LOCAL # default when NODE_ENV=development
SERVERLESS_TYPE=LOCAL # default
```
**Pentru producție (AWS):**
```bash
LOGIC_FUNCTION_TYPE=LAMBDA
LOGIC_FUNCTION_LAMBDA_REGION=us-east-1
LOGIC_FUNCTION_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID=your-access-key
LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
SERVERLESS_TYPE=LAMBDA
SERVERLESS_LAMBDA_REGION=us-east-1
SERVERLESS_LAMBDA_ROLE=arn:aws:iam::123456789:role/your-lambda-role
SERVERLESS_LAMBDA_ACCESS_KEY_ID=your-access-key
SERVERLESS_LAMBDA_SECRET_ACCESS_KEY=your-secret-key
```
**Pentru a dezactiva funcțiile logice:**
```bash
LOGIC_FUNCTION_TYPE=DISABLED # default when NODE_ENV=production
SERVERLESS_TYPE=DISABLED
```
### Interpretor de cod - Drivere disponibile
| Driver | Variabilă de mediu | Caz de utilizare | Nivel de securitate |
| ---------- | -------------------------------- | ---------------------------------------- | ------------------------ |
| Dezactivat | `CODE_INTERPRETER_TYPE=DISABLED` | Dezactivați execuția codului de către AI | N/A |
| Local | `CODE_INTERPRETER_TYPE=LOCAL` | Doar pentru dezvoltare | Scăzut (fără sandboxing) |
| E2B | `CODE_INTERPRETER_TYPE=E_2_B` | Producție cu execuție în sandbox | Ridicat (sandbox izolat) |
<Note>
Când utilizați `LOGIC_FUNCTION_TYPE=DISABLED` sau `CODE_INTERPRETER_TYPE=DISABLED`, orice încercare de execuție va returna o eroare. Acest lucru este util dacă doriți să rulați Twenty fără aceste capabilități.
Când se utilizează `SERVERLESS_TYPE=DISABLED`, orice încercare de a executa o funcție logică va returna o eroare. Acest lucru este util dacă doriți să rulați Twenty fără capabilități de funcții logice.
</Note>

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