snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,262 @@
---
title: Docker Compose
icon: docker
---
<Warning>
Docker 容器适用于生产环境托管或自托管。 如需参与贡献,请查看[本地设置](/l/zh/developers/contribute/capabilities/local-setup)。
</Warning>
## 概览
本指南提供了使用Docker Compose安装和配置Twenty应用程序的分步说明。 其目的是使过程简单明了,并防止可能造成设置中断的常见错误。
**重要:** 仅修改本指南中明确提到的设置。 更改其他配置可能会导致问题。
有关高级配置,请参阅[设置环境变量](/l/zh/developers/self-host/capabilities/setup)。 所有环境变量必须在 `docker-compose.yml` 文件中声明,具体在服务器和/或 worker 层级,取决于变量。
## 系统要求
* RAM:确保您的环境至少有2GB的RAM。 内存不足会导致进程崩溃。
* Docker & Docker Compose:确保两者均已安装并是最新的。
## 选项 1:单行脚本
通过简单的命令安装最新的Twenty稳定版本:
```bash
bash <(curl -sL https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-docker/scripts/install.sh)
```
要安装特定版本或分支:
```bash
VERSION=vx.y.z BRANCH=branch-name bash <(curl -sL https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-docker/scripts/install.sh)
```
* 将x.y.z替换为所需的版本号。
* 将branch-name替换为您要安装的分支名称。
## 选项 2:手动步骤
请按以下步骤进行手动设置。
### 步骤 1:设置环境文件
1. **创建 .env 文件**
将示例环境文件复制到工作目录中的新.env文件:
```bash
curl -o .env https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-docker/.env.example
```
2. **生成加密密钥**
运行以下命令以生成唯一的随机字符串:
```bash
openssl rand -base64 32
```
**重要:** 保持该值秘密/不要共享。 丢失 `ENCRYPTION_KEY` 意味着将失去对数据库中存储的所有机密信息(OAuth 令牌、应用程序变量、TOTP 机密等)的访问权限。
3. **更新`.env`**
用生成的令牌替换.env文件中的占位符值:
```ini
ENCRYPTION_KEY=random_string
```
有关在不停机的情况下轮换密钥的说明,请参阅[密钥轮换指南](/l/zh/developers/self-host/capabilities/key-rotation)。
4. **设置Postgres密码**
用不含特殊字符的强密码更新.env文件中的`PG_DATABASE_PASSWORD`值。
```ini
PG_DATABASE_PASSWORD=my_strong_password
```
### 步骤2:获取Docker Compose文件
将`docker-compose.yml`文件下载到工作目录:
```bash
curl -o docker-compose.yml https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-docker/docker-compose.yml
```
### 步骤3:启动应用程序
启动Docker容器:
```bash
docker compose up -d
```
### 步骤4:访问应用程序
如果您在自己的电脑上托管twentyCRM,打开浏览器并导航到[http://localhost:3000](http://localhost:3000)。
如果您在服务器上托管它,请检查服务器是否正在运行并确保一切正常。
```bash
curl http://localhost:3000
```
## 配置
### 将Twenty暴露给外部访问
默认情况下,Twenty在`localhost`的端口`3000`上运行。 UI 会基于浏览器自身的源(origin)解析 API 地址,因此它可以从任何能访问该容器的主机名加载——但仍需要将 `SERVER_URL` 设置为你的公共 URL:服务器会用它来生成链接(邮件、OAuth 回调),并据此检测是否启用 HTTPS,以设置安全 Cookie。
#### 理解`SERVER_URL`
* **协议:** 根据您的设置,使用`http`或者`https`。
* 如果您没有设置SSL,请使用`http`。
* 如果已配置SSL,请使用`https`。
* **域名/IP:** 这是您的应用程序可访问的域名或IP地址。
* **端口:** 如果您没有使用默认端口(`http`为80,`https`为443),请包括端口号。
### SSL要求
某些浏览器功能需要SSL(HTTPS)才能正常工作。 虽然这些功能在本地开发期间可能正常工作(因为浏览器对待localhost不同),但在常规域上托管Twenty时需要正确的SSL设置。
例如,剪贴板API可能需要安全的上下文 - 一些功能如整个应用程序中的复制按钮可能在未启用HTTPS时无法使用。
我们强烈建议您在带有SSL终止的反向代理背后设置Twenty,以实现最佳的安全性和功能。
#### 配置`SERVER_URL`
1. **确定您的访问URL**
* **没有反向代理(直接访问):**
如果您直接访问应用程序而没有反向代理:
```ini
SERVER_URL=http://your-domain-or-ip:3000
```
* **有反向代理(标准端口):**
如果您使用像Nginx或Traefik这样的反向代理并配置了SSL:
```ini
SERVER_URL=https://your-domain-or-ip
```
* **有反向代理(自定义端口):**
如果您使用非标准端口:
```ini
SERVER_URL=https://your-domain-or-ip:custom-port
```
2. **更新`.env`文件**
打开您的`.env`文件并更新`SERVER_URL`:
```ini
SERVER_URL=http(s)://your-domain-or-ip:your-port
```
**示例:**
* 无需SSL的直接访问:
```ini
SERVER_URL=http://123.45.67.89:3000
```
* 通过域名访问使用SSL:
```ini
SERVER_URL=https://mytwentyapp.com
```
3. **重新启动应用程序**
为了让更改生效,重启Docker容器:
```bash
docker compose down
docker compose up -d
```
#### 注意事项
* **反向代理配置:**
确保您的反向代理将请求转发到正确的内部端口(默认情况下为`3000`)。 配置 SSL 终止和任何必要的头信息。
* **防火墙设置:**
打开防火墙中的必要端口以允许外部访问。
* **一致性:**
`SERVER_URL` 必须与用户在浏览器中访问您的应用程序的方式匹配。
#### 数据持久化
* **数据卷:**
Docker Compose 配置使用卷来持久化数据库和服务器存储的数据。
* **无状态环境:**
如果部署到无状态环境(例如,某些云服务),请配置外部存储以持久化数据。
## 备份与恢复
定期备份可保护您的 CRM 数据免于丢失。
### 创建数据库备份
```bash
docker exec twenty-postgres pg_dump -U postgres twenty > backup_$(date +%Y%m%d).sql
```
### 自动化每日备份
将以下内容添加到您的 crontab(`crontab -e`):
```bash
0 2 * * * docker exec twenty-postgres pg_dump -U postgres twenty > /backups/twenty_$(date +\%Y\%m\%d).sql
```
### 从备份恢复
1. 停止应用程序:
```bash
docker compose stop server worker
```
2. 恢复数据库:
```bash
docker exec -i twenty-postgres psql -U postgres twenty < backup_20240115.sql
```
3. 重启服务:
```bash
docker compose up -d
```
### 备份最佳实践
* **定期测试恢复** — 验证备份确实有效
* **将备份异地存储** — 使用云存储(S3、GCS 等)
* **加密敏感数据** — 使用加密保护备份
* **保留多份副本** — 同时保留每日、每周和每月的备份
## 故障排除
如果您遇到任何问题,请检查[故障排除](/l/zh/developers/self-host/capabilities/troubleshooting)以获取解决方案。
## 托管服务
<Tip>
不想自己运行和维护 Twenty 吗? [寻找经过认证的 Twenty 托管合作伙伴](https://twenty.com/partners/list?categories=HOSTING\&ref=docs-docker-compose) 来端到端部署、托管和管理你的实例。 *(或者联系我们的团队: [contact@twenty.com](mailto:contact@twenty.com)。)*
</Tip>

View File

@@ -0,0 +1,60 @@
---
title: 密钥轮换
icon: rotate
---
Twenty 具有两个相互独立的密钥族:
* **JWT 签名密钥** — 存储在 `core."signingKey"` 中、带有 `kid` 标签的非对称 ES256 密钥对,用于对访问令牌 / 刷新令牌进行签名和验证。
* **静态加密密钥** — `ENCRYPTION_KEY`,用于在 `enc:v2:` 封装中加密 OAuth 令牌、应用变量、签名密钥私钥、敏感配置值和 TOTP 密钥。
`APP_SECRET` 是为向后兼容而保留的旧版密钥:当未设置 `ENCRYPTION_KEY` 时,它充当静态加密 / 会话 Cookie 的后备密钥,并且仍会验证已有的 HS256 访问令牌。 它将被弃用。
## JWT 签名密钥
每个密钥都包含一个 `publicKey`(无限期保留,以便验证之前签发的令牌)、一个加密的 `privateKey`(仅在该密钥为当前密钥时使用)、一个 `isCurrent` 标志(同一时间只有一行为当前),以及一个可选的 `revokedAt`。
### 轮换当前密钥
将 `SIGNING_KEY_ROTATION_DAYS` 设为启用该功能:然后每日的 cron 任务会在现有密钥超过该阈值后签发新的当前密钥。 先前的密钥*不会*被吊销,因此在其下签名的令牌仍然可以通过验证。 将变量保持未设置以禁用自动轮换。
<Note>自动轮换在 v2.6+ 中提供。</Note>
### 吊销密钥(仅限泄露 / 紧急情况)
在非当前行上执行 **Settings → Admin Panel → Signing keys → Revoke**。 会清除加密的私有材料,设置 `revokedAt`,并拒绝在该 `kid` 下签名的所有现有令牌。
## 轮换 `ENCRYPTION_KEY`
<Note>下面描述的 `secret-encryption:rotate` 命令从 v2.6+ 版本开始提供。</Note>
每个加密值都封装为 `enc:v2:\<keyId>:\<payload>`,其中 `\<keyId>` 是从原始密钥派生出的 8 位十六进制前缀。 轮换是在线且可恢复的。
1. **生成新密钥**:`openssl rand -base64 32`。
2. **在 `.env` 中并排配置两个密钥**,然后重启:
```ini
ENCRYPTION_KEY=NEW_VALUE
FALLBACK_ENCRYPTION_KEY=OLD_VALUE
```
新的写入使用新密钥,现有行仍通过后备密钥解密。
3. **重新加密现有行**:
```bash
docker exec -it {server_container} yarn command:prod secret-encryption:rotate
```
该命令会遍历六个位置(`connected-account-tokens`、`application-variable`、`application-registration-variable`、`signing-key-private-keys`、`sensitive-config-storage`、`totp-secrets`)。 SQL 过滤器会跳过已使用新 `\<keyId>` 的行,因此该命令是幂等的:可根据需要中断并重新运行。 如果任意一行失败则以非零状态退出 — 重新运行以重试。
| 标志 | 描述 |
| ---------------------------------------- | ---------------------------- |
| `-s, --site \<site>` | 仅限单个位置。 |
| `-b, --batch-size \<n>` | 每批处理的行数(默认 `200`,最大 `5000`)。 |
| `-d, --dry-run` | 在内存中解密并重新加密,跳过 `UPDATE`。 |
4. 一旦 `--dry-run` 显示没有剩余行,就**删除后备密钥**:移除 `FALLBACK_ENCRYPTION_KEY` 并重启。
## 旧版 `APP_SECRET` 支持
从未设置 `ENCRYPTION_KEY` 的旧实例会使用 `APP_SECRET` 作为静态加密密钥(以及会话 Cookie 密钥,从中派生)。 此路径为向后兼容而保留,但已被**弃用** — 请设置专用的 `ENCRYPTION_KEY`,并按照上述轮换流程迁移离开它。 `APP_SECRET` 本身仍用于验证旧版 HS256 访问令牌。

View File

@@ -0,0 +1,408 @@
---
title: 设置
icon: gear
---
# 配置管理
<Warning>
**第一次安装?** 请按照 [Docker Compose 安装指南](/l/zh/developers/self-host/capabilities/docker-compose) 获得 Twenty 运行,然后返回此处进行配置。
</Warning>
Twenty 提供**两种配置模式**以适应不同的部署需求:
**管理员面板访问:** 只有具有管理员权限的用户(`canAccessFullAdminPanel: true`) 可以访问配置界面。
## 1. 管理员面板配置(默认)
```bash
IS_CONFIG_VARIABLES_IN_DB_ENABLED=true # default
```
**大多数配置在安装后通过 UI 进行:**
1. 访问你的 Twenty 实例(通常为 `http://localhost:3000`)
2. 转到 **设置 / 管理员面板 / 配置变量**
3. 配置集成、电子邮件、存储等
4. 更改会立即生效(多容器部署在 15 秒内)
<Warning>
**多容器部署:** 当使用数据库配置(`IS_CONFIG_VARIABLES_IN_DB_ENABLED=true`)时,server 和 worker 容器都会从同一个数据库读取。 管理员面板更改会自动影响两者,无需在容器之间重复环境变量(基础设施变量除外)。
</Warning>
**通过管理员面板可以配置的内容:**
* **身份验证** - Google/Microsoft OAuth、密码设置
* **电子邮件** - SMTP 设置、模板、验证
* **存储** - S3 配置、本地存储路径
* **集成** - Gmail, Google Calendar, Microsoft 服务
* **工作流和速率限制** - 执行限制、API 限流
* **还有更多……**
![管理员面板配置变量](/images/user-guide/setup/admin-panel-config-variables.png)
<Warning>
每个变量都在您的管理面板的**设置 → 管理员面板 → 配置变量**中记录了说明。
某些基础设施设置如数据库连接 (`PG_DATABASE_URL`)、服务器 URL (`SERVER_URL`) 和密钥(`ENCRYPTION_KEY`、`FALLBACK_ENCRYPTION_KEY`)只能通过 `.env` 文件配置。
[完整技术参考→](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts)
</Warning>
## 加密密钥
Twenty 使用两个仅通过环境变量配置的加密密钥:
| 变量 | 目的 | 必填 |
| ------------------------- | ------------------------------------------------------------ | ------------------------------------- |
| `ENCRYPTION_KEY` | 用于对静态存储的机密信息(OAuth 令牌、应用程序变量、签名密钥的私钥、TOTP 密钥、敏感配置值)进行加密的主密钥。 | 新安装必须设置(旧安装可能依赖于 `APP_SECRET` —— 见下文) |
| `FALLBACK_ENCRYPTION_KEY` | 仅用于验证的密钥。 在轮换期间,将其设置为*先前的* `ENCRYPTION_KEY`,以便现有行仍可解密。 | 仅在轮换期间 |
为保持向后兼容性,如果未设置 `ENCRYPTION_KEY`,Twenty 将回退为使用 `APP_SECRET` 进行静态数据加密——与旧部署的旧版行为一致。 新的安装应始终设置专用的 `ENCRYPTION_KEY`。
使用 `openssl rand -base64 32` 生成值,并将其安全存储(如密钥管理器、加密配置等)。 丢失 `ENCRYPTION_KEY` 意味着将失去对数据库中存储的所有机密的访问权限。
要在不停机的情况下轮换 `ENCRYPTION_KEY`,请参阅[密钥轮换指南](/l/zh/developers/self-host/capabilities/key-rotation)。
## 2. 仅限环境配置
```bash
IS_CONFIG_VARIABLES_IN_DB_ENABLED=false
```
**所有配置通过 `.env` 文件管理:**
1. 在 `.env` 文件中设置 `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false`
2. 将所有配置变量添加到 `.env` 文件中
3. 重启容器以使更改生效
4. 管理员面板将显示当前值,但无法修改它们
## 多工作区模式
默认情况下,Twenty 以**单工作区模式**运行——对于大多数需要为组织部署一个 CRM 实例的自托管部署而言,这是理想之选。
### 单工作区模式(默认)
```bash
IS_MULTIWORKSPACE_ENABLED=false # default
```
* 每个 Twenty 实例一个工作区
* 首位用户会自动成为具有完整权限的管理员(`canImpersonate` 和 `canAccessFullAdminPanel`)
* 创建第一个工作区后,新注册将被禁用
* 简单的 URL 结构:`https://your-domain.com`
### 启用多工作区模式
```bash
IS_MULTIWORKSPACE_ENABLED=true
DEFAULT_SUBDOMAIN=app # default value
```
对于在同一 Twenty 实例上需要多个独立团队拥有各自工作区的类 SaaS 部署,启用多工作区模式。
**与单工作区模式的关键区别:**
* 同一实例上可以创建多个工作区
* 每个工作区都有其自己的子域(例如,`sales.your-domain.com`、`marketing.your-domain.com`)
* 用户在 `{DEFAULT_SUBDOMAIN}.your-domain.com` 进行注册和登录(例如,`app.your-domain.com`)
* 不自动授予管理员权限——每个工作区的首位用户是普通用户
* 子域、自定义域名等与工作区相关的设置将在工作区设置中可用。
<Warning>
**仅限环境的设置:**`IS_MULTIWORKSPACE_ENABLED` 只能通过 `.env` 文件进行配置,并且需要重启。 无法通过管理面板进行更改。
</Warning>
### 多工作区模式的 DNS 配置
使用多工作区模式时,请在 DNS 中配置通配符记录,以允许动态创建子域:
```
*.your-domain.com -> your-server-ip
```
这使新工作区能够在无需手动配置 DNS 的情况下自动进行子域路由。
### 限制工作区创建
在多工作区模式下,你可能希望限制谁可以创建新工作区:
```bash
IS_WORKSPACE_CREATION_LIMITED_TO_SERVER_ADMINS=true
```
启用后,只有具有 `canAccessFullAdminPanel` 权限的用户才能创建其他工作区。 用户仍可在首次注册时创建他们的第一个工作区。
## Gmail & Google Calendar 集成
### 创建 Google 云项目
1. 转到 [Google 云控制台](https://console.cloud.google.com/)
2. 创建新项目或选择现有项目
3. 启用这些 API:
* [Gmail API](https://console.cloud.google.com/apis/library/gmail.googleapis.com)
* [Google Calendar API](https://console.cloud.google.com/apis/library/calendar-json.googleapis.com)
* [People API](https://console.cloud.google.com/apis/library/people.googleapis.com)
### 配置 OAuth
1. 转到 [凭据](https://console.cloud.google.com/apis/credentials)
2. 创建 OAuth 2.0 客户端 ID
3. 添加这些重定向 URI:
* `https://{your-domain}/auth/google/redirect` (用于 SSO)
* `https://{your-domain}/auth/google-apis/get-access-token` (用于集成)
### 在 Twenty 中配置
1. 转到 **设置 → 管理员面板 → 配置变量**
2. 找到 **Google 身份验证** 部分
3. 设置这些变量:
* `MESSAGING_PROVIDER_GMAIL_ENABLED=true`
* `CALENDAR_PROVIDER_GOOGLE_ENABLED=true`
* `AUTH_GOOGLE_CLIENT_ID={client-id}`
* `AUTH_GOOGLE_CLIENT_SECRET={client-secret}`
* `AUTH_GOOGLE_CALLBACK_URL=https://{your-domain}/auth/google/redirect`
* `AUTH_GOOGLE_APIS_CALLBACK_URL=https://{your-domain}/auth/google-apis/get-access-token`
<Warning>
**仅限环境模式:** 如果你设置 `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false`,请将这些变量添加到 `.env` 文件中。
</Warning>
**所需范围**(自动配置):
[查看相关源码](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/auth/utils/get-google-apis-oauth-scopes.ts#L4-L10)
* `https://www.googleapis.com/auth/calendar.events`
* `https://www.googleapis.com/auth/gmail.readonly`
* `https://www.googleapis.com/auth/profile.emails.read`
### 如果你的应用程序处于测试模式
如果你的应用程序处于测试模式,你需要将测试用户添加到你的项目中。
在 [OAuth 同意屏幕](https://console.cloud.google.com/apis/credentials/consent) 下,将你的测试用户添加到 "测试用户" 部分。
## Microsoft 365 集成
<Warning>
用户必须拥有 [Microsoft 365 许可证](https://admin.microsoft.com/Adminportal/Home) 才能使用日历和消息传递 API。 没有许可证,他们将无法在 Twenty 上同步他们的帐户。
</Warning>
### 在 Microsoft Azure 中创建项目
你需要在 [Microsoft Azure](https://portal.azure.com/#view/Microsoft_AAD_IAM/AppGalleryBladeV2) 中创建项目并获取凭据。
### 启用 API
在 Microsoft Azure 控制台中的“权限”中启用以下 API:
* Microsoft Graph: Mail.ReadWrite
* Microsoft Graph: Mail.Send
* Microsoft Graph: Calendars.Read
* Microsoft Graph: User.Read
* Microsoft Graph: openid
* Microsoft Graph: email
* Microsoft Graph: profile
* Microsoft Graph: offline_access
<Note>
“Mail.ReadWrite”和“Mail.Send”仅在你想使用我们的工作流程操作发送电子邮件时是必需的。 如果你只想接收邮件,你可以使用“Mail.Read”。
</Note>
<Note>
如果你想使用我们的工作流操作创建日历事件,则必须使用 "Calendars.ReadWrite"。 如果你只想同步日历事件,请使用 "Calendars.Read"。
</Note>
### 授权重定向 URI
你需要将以下重定向 URI 添加到你的项目中:
* `https://{your-domain}/auth/microsoft/redirect` 如果你想使用 Microsoft SSO
* `https://{your-domain}/auth/microsoft-apis/get-access-token`
### 在 Twenty 中配置
1. 转到 **设置 → 管理员面板 → 配置变量**
2. 找到 **Microsoft 身份验证** 部分
3. 设置这些变量:
* `MESSAGING_PROVIDER_MICROSOFT_ENABLED=true`
* `CALENDAR_PROVIDER_MICROSOFT_ENABLED=true`
* `AUTH_MICROSOFT_ENABLED=true`
* `AUTH_MICROSOFT_CLIENT_ID={client-id}`
* `AUTH_MICROSOFT_CLIENT_SECRET={client-secret}`
* `AUTH_MICROSOFT_CALLBACK_URL=https://{your-domain}/auth/microsoft/redirect`
* `AUTH_MICROSOFT_APIS_CALLBACK_URL=https://{your-domain}/auth/microsoft-apis/get-access-token`
<Warning>
**仅限环境模式:** 如果你设置 `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false`,请将这些变量添加到 `.env` 文件中。
</Warning>
### 配置范围
[查看相关源码](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/auth/utils/get-microsoft-apis-oauth-scopes.ts#L2-L9)
* 'openid'
* '电子邮件'
* '个人资料'
* 'offline_access'
* 'Mail.ReadWrite'
* 'Mail.Send'
* 'Calendars.Read'
### 如果你的应用程序处于测试模式
如果你的应用程序处于测试模式,你需要将测试用户添加到你的项目中。
将你的测试用户添加到“用户和组”部分。
## 日历和消息传递的后台作业
在配置完 Gmail、Google Calendar 或 Microsoft 365 集成后,你需要启动同步数据的后台作业。
在你的工作容器中注册以下重复作业:
```bash
# from your worker container
yarn command:prod cron:messaging:messages-import
yarn command:prod cron:messaging:message-list-fetch
yarn command:prod cron:calendar:calendar-event-list-fetch
yarn command:prod cron:calendar:calendar-events-import
yarn command:prod cron:messaging:ongoing-stale
yarn command:prod cron:calendar:ongoing-stale
yarn command:prod cron:workflow:automated-cron-trigger
```
## 电子邮件配置
1. 转到 **设置 → 管理员面板 → 配置变量**
2. 找到 **电子邮件** 部分
3. 配置你的 SMTP 设置:
<Tabs>
<Tab title="Gmail">
你需要提供一个 [应用密码](https://support.google.com/accounts/answer/185833)。
* EMAIL_DRIVER=smtp
* EMAIL_SMTP_HOST=smtp.gmail.com
* EMAIL_SMTP_PORT=465
* EMAIL_SMTP_USER=gmail_email_address
* EMAIL_SMTP_PASSWORD='gmail_app_password'
</Tab>
<Tab title="Office365">
请记住,如果您启用了双重身份验证,您需要提供一个 [应用密码](https://support.microsoft.com/en-us/account-billing/manage-app-passwords-for-two-step-verification-d6dc8c6d-4bf7-4851-ad95-6d07799387e9)。
* EMAIL_DRIVER=smtp
* EMAIL_SMTP_HOST=smtp.office365.com
* EMAIL_SMTP_PORT=587
* EMAIL_SMTP_USER=office365_email_address
* EMAIL_SMTP_PASSWORD='office365_password'
</Tab>
<Tab title="smtp4dev">
**smtp4dev** 是一个用于开发和测试的假 SMTP 电子邮件服务器。
* 运行 smtp4dev 镜像: `docker run --rm -it -p 8090:80 -p 2525:25 rnwood/smtp4dev`
* 在此处访问 smtp4dev UI:[http://localhost:8090](http://localhost:8090)
* 设置以下变量:
* EMAIL_DRIVER=smtp
* EMAIL_SMTP_HOST=localhost
* EMAIL_SMTP_PORT=2525
</Tab>
</Tabs>
<Warning>
**仅限环境模式:** 如果你设置 `IS_CONFIG_VARIABLES_IN_DB_ENABLED=false`,请将这些变量添加到 `.env` 文件中。
</Warning>
## S3 存储
<Warning>
默认情况下,Twenty 将上传的文件存储在本地文件系统上。 对于生产环境部署,请使用 S3 或兼容 S3 的服务(MinIO、DigitalOcean Spaces 等)。 以确保文件在容器重启后仍然存在,并可在多个服务器实例间扩展。
</Warning>
设置 `STORAGE_TYPE=S_3`,并通过管理面板或 `.env` 配置 `STORAGE_S3_*` 变量。 有关 S3 变量的完整列表,请参见[config-variables.ts 参考](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts)。
在将 S3 与依赖 CORS 的功能(例如浏览器内文件下载)一起使用时,请确保你的存储桶在其 CORS 配置中允许你的 Twenty 前端来源。
## 逻辑函数与代码解释器
Twenty 支持用于工作流的逻辑函数,以及用于 AI 数据分析的代码解释器。 二者都会运行用户提供的代码,并要求进行显式配置以确保安全。
### 安全默认设置
**在生产环境(NODE_ENV=production):** 逻辑函数和代码解释器的默认设置为**禁用**。 如需这些功能,必须通过 `LOGIC_FUNCTION_TYPE` 和 `CODE_INTERPRETER_TYPE` 显式启用它们。
**在开发环境(NODE_ENV=development):** 为方便在本地运行,二者默认均为**LOCAL**。
<Warning>
**安全提示:** 本地驱动(`LOGIC_FUNCTION_TYPE=LOCAL` 或 `CODE_INTERPRETER_TYPE=LOCAL`)会在没有沙箱的情况下,在主机上的 Node.js 进程中直接运行代码。 它应仅在开发环境中用于可信代码。 对于在生产环境中处理不受信任代码的部署,请使用 `LOGIC_FUNCTION_TYPE=LAMBDA` 或 `CODE_INTERPRETER_TYPE=E2B`(使用沙盒),或将它们保持禁用。
</Warning>
### 逻辑函数 - 可用驱动程序
| 驱动 | 环境变量 | 用例 | 安全级别 |
| ------ | ------------------------------ | -------------- | -------- |
| 禁用 | `LOGIC_FUNCTION_TYPE=DISABLED` | 完全禁用逻辑函数 | 不适用 |
| 本地 | `LOGIC_FUNCTION_TYPE=LOCAL` | 开发和可信环境 | 低(无沙箱) |
| Lambda | `LOGIC_FUNCTION_TYPE=LAMBDA` | 生产环境(处理不受信任代码) | 高(硬件级隔离) |
### 逻辑函数 - 推荐配置
**用于开发:**
```bash
LOGIC_FUNCTION_TYPE=LOCAL # default when NODE_ENV=development
```
**用于生产(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
```
**要禁用逻辑函数:**
```bash
LOGIC_FUNCTION_TYPE=DISABLED # default when NODE_ENV=production
```
### 代码解释器 - 可用驱动程序
| 驱动 | 环境变量 | 用例 | 安全级别 |
| --- | -------------------------------- | ----------- | ------- |
| 禁用 | `CODE_INTERPRETER_TYPE=DISABLED` | 禁用 AI 代码执行 | 不适用 |
| 本地 | `CODE_INTERPRETER_TYPE=LOCAL` | 仅限开发环境 | 低(无沙箱) |
| E2B | `CODE_INTERPRETER_TYPE=E_2_B` | 生产环境(沙盒化执行) | 高(隔离沙盒) |
<Note>
当使用 `LOGIC_FUNCTION_TYPE=DISABLED` 或 `CODE_INTERPRETER_TYPE=DISABLED` 时,任何执行尝试都会返回错误。 如果你想在不启用这些功能的情况下运行 Twenty,这将很有用。
</Note>
## API 和前端位于不同主机上
仅当你不让后端来提供前端资源时,此项才相关。 同源部署在这里无需任何设置。
声明每一个与 API 通信的浏览器来源(origin),使用逗号分隔。 `SERVER_URL`
和 `FRONTEND_URL` 已被信任。 当浏览器从未声明的来源调用它时,服务器会记录一条警告日志。
```bash
AUTH_COOKIE_ALLOWED_ORIGINS=https://app.example.com
```
<Warning>
前端会在每个请求中发送凭据,而浏览器会拒绝来自未声明源的携带凭据的响应,因此在你完成此设置之前,应用将无法加载。
</Warning>
如果这两个主机位于不同的可注册域(不仅仅是不同的子域),还需要设置 `AUTH_COOKIE_SAME_SITE=none`,并且这要求使用 HTTPS。
在启用多工作区功能时,不要在此列出每个工作区的子域名。
相反,请在每个工作区主机名上将 API 路径(`/graphql`、`/metadata`、`/rest`、`/auth/`、`/client-config`、`/file`)路由到后端,这样每个工作区都保持同源 —— 这正是 Twenty Cloud 的运行方式。

View File

@@ -0,0 +1,254 @@
---
title: 故障排除
icon: wrench
---
## 故障排除
如果您在设置开发环境、升级实例或自托管时遇到任何问题,这里有一些常见问题的解决方案。
### 自托管
#### 首次安装时出现“密码认证失败,用户为"postgres"”
🚨 **重要:此解决方案仅适用于全新安装** 🚨
如果您有一个现有的 Twenty 实例和生产数据,请**不要**按照这些步骤操作,因为这些步骤会永久删除您的数据库!
在首次安装 Twenty 时,您可能想更改默认的数据库密码。
您在首次安装时设置的密码会永久存储在数据库卷中。 如果以后尝试在配置中更改此密码而不移除旧卷,则会出现身份验证错误,因为数据库仍在使用原密码。
⚠️ 警告:以下步骤将永久删除所有数据库数据! ⚠️
仅在这是一项没有重要数据的新安装时继续。
若要更新`PG_DATABASE_PASSSWORD`,您需要:
```sh
# Update the PG_DATABASE_PASSWORD in .env
docker compose down --volumes
docker compose up -d
```
#### 发现 CR 换行符 [Windows]
发生这种情况的原因是Windows行尾字符与您的Git配置。 尝试运行:
```
git config --global core.autocrlf false
```
然后删除存储库并再次克隆。
#### 缺少元数据架构
在安装 Twenty 时,您需要为您的 postgres 数据库提供正确的模式、扩展和用户。
如果您成功进行了此配置,数据库中应有 `default` 和 `metadata` 模式。
如果您没有,请确保您的电脑上没有一个以上的 PostgreSQL 实例。
#### 找不到模块 'twenty-emails' 或其相应的类型声明。
在运行数据库初始化之前,您必须先构建`twentemails`软件包(`npx nx 运行 twentemails:build`)。
#### 缺少 twenty-x 包
确保在根目录运行 yarn,然后运行 `npx nx server:dev twenty-server`。 如果这依然不工作,尝试手动构建缺失的包。
#### 保存时 Lint 不起作用
这应在安装了 Oxc 扩展 (`oxc.oxc-vscode`) 后即可正常工作。 如果这不起作用,请尝试将其添加到您的 VS 代码设置(dev container scope):
```
"editor.codeActionsOnSave": {
"source.fixAll.oxc": "explicit"
}
```
#### 在运行 `npx nx start` 或 `npx nx start twent` 时,出现了一个内存错误
仅运行您需要的服务,而不是 `npx nx start`。 例如,如果您在服务器上工作,仅运行 `npx nx worker twenty-server`
**如果不起作用:**
如果您尝试在 WSL 上仅运行 `npx nx run twenty-server:start` 但因以下内存错误而失败:
`致命错误:无效标记-压缩接近堆限制 分配失败 - JavaScript 堆内存不足`
解决方案是在您的终端中运行以下命令,或将其添加到您的`.bashrc`配置文件中,所以它自动应用:
`export NODE_OPTIONS="--max-old-space-size=8192"`
\--max-old-space-size=8192 标志为 Node.js 堆设置了 8GB 的上限;使用会根据应用程序需求进行扩展。
参考:https://stackoverflow.com/questions/56982005/where-do-i-set-node-options-max-old-space-size-2048
**如果它不能工作:**
调查哪些进程正在占用你机器的大部分RAM。 20时,我们注意到一些VS 代码扩展占用了大量内存,所以我们暂时禁用了它们。
**如果它不起作用:**
重启你的机器有助于清理幽灵过程。
#### 运行 `npx nx start` 时日志中出现奇怪的 [0] 和 [1]
预期的情况,由于 npx nx start 命令在后台运行更多命令
#### 没有发送电子邮件
大多数情况下,是因为 `worker` 没有在后台运行。 尝试运行
```
npx nx worker twenty-server
```
#### 无法连接我的 Microsoft 365 帐户到 20ty
大多数情况下,这是因为管理员没有为您的账户启用 Microsoft 365 许可证。 访问 [https://admin.microsoft.com/](https://admin.microsoft.com/Adminportal/Home)。
如果您收到错误代码 `AADSTS50020`,这可能意味着您正在使用个人 Microsoft 账户。 这尚不支持。 更多信息 [请访问这里](https://learn.microsoft.com/fr-fr/troubleshoot/entra/entra-id/app-integration/error-code-aadsts50020-user-account-identity-provider-does-not-exist)
#### 在运行 `yarn`时,警告会出现在控制台中
警告信息是为了告知您正在拉取额外且未在 `package.json` 中明确声明的依赖,只要没有发生严重错误,一切应该会按预期工作。
#### 当用户访问登录页面时,一个未经授权的用户试图访问工作区的错误会出现在日志中。
由于用户身份尚未得到验证,因此用户在登出时可能未被授权。
#### 如何检查您的 worker 是否在运行?
* 访问 [webhook-test.com](https://webhook-test.com/) 并复制 **您的唯一 Webhook URL**。
<div style={{textAlign: 'center'}}>
<img src="/images/docs/developers/self-hosting/webhook-test.jpg" alt="Webhook 测试" />
</div>
* 打开您的 Twenty 应用,导航到 `/settings`,并在屏幕左下角启用 **高级** 切换。
* 创建一个新的 webhook。
* 把 **您的唯一 Webhook URL** 粘贴在 Twenty 的 **Endpoint Url** 字段中。 将 **筛选器** 设置为 `Companies` 和 `Created`。
<div style={{textAlign: 'center'}}>
<img src="/images/docs/developers/self-hosting/webhook-settings.jpg" alt="Webhook 设置" />
</div>
* 转到 `/objects/companies` 并创建一个新的公司记录。
* 返回 [webhook-test.com](https://webhook-test.com/) ,查看是否收到新的 **POST 请求**。
<div style={{textAlign: 'center'}}>
<img src="/images/docs/developers/self-hosting/webhook-test-result.jpg" alt="Webhook 测试结果" />
</div>
* 如果收到 **POST 请求**,则说明您的 worker 正在成功运行。 否则,您需要对 worker 进行故障排除。
#### 前端未能启动,返回错误 TS5042: 选项'project' 不能与命令行上的源文件混合。
评论`packes/twoi/vite-config.ts`中的检查器插件,如下所示:
```
plugins: [
react({ jsxImportSource: 'react' }),
tsconfigPaths(),
svgr(),
dts(dtsConfig),
// checker(checkersConfig),
wyw({
include: [
'**/OverflowingTextWithTooltip.tsx',
'**/Chip.tsx',
'**/Tag.tsx',
'**/Avatar.tsx',
'**/AvatarChip.tsx',
],
babelOptions: {
presets: ['@babel/preset-typescript', '@babel/preset-react'],
},
}),
],
```
#### 无法访问管理面板
在数据库容器中运行 `updatE core."user" SET "canAccessFullAdminPanel" = TRUE WHERE email = 'you@yourdomain.com';` 以获得管理面板的访问权限。
#### 在运行工作流时,工作流运行失败,并提示 "Logic function execution is disabled." 将 LOGIC_FUNCTION_TYPE 设置为 LOCAL 或 LAMBDA 以启用。
在生产环境中,逻辑函数默认处于禁用状态。 将 `LOGIC_FUNCTION_TYPE` 环境变量设置为 `LOCAL` 或 `LAMBDA` 以启用它们。 这可以通过环境变量或管理面板的数据库变量进行配置。 详情请参见[逻辑函数设置指南](/l/zh/developers/self-host/capabilities/setup#logic-functions-available-drivers)。
#### 当我在 AI 聊天中输入消息时,它不会立即回答,我必须刷新页面才能看到答案
这意味着您的逆向代理缺少基于流 API 响应的配置。 下面是 Nginx 配置的示例:
```
location ~* ^/api/.*stream|\/graphql\/stream {
proxy_pass http://twenty_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
proxy_cache off;
gzip off;
#chunked_transfer_encoding off;
add_header X-Accel-Buffering no always;
}
```
### 单击Docker 配置
#### 无法登录
如果您在设置后无法登录:
1. 运行以下命令:
```bash
docker exec -it twenty-server-1 yarn
docker exec -it twenty-server-1 npx nx database:reset --configuration=no-seed
```
2. 重启 Docker 容器:
```bash
docker compose down
docker compose up -d
```
请注意,`database:reset`命令将完全擦除您的数据库并从头重新创建它。
#### 反向代理后面的连接问题
如果您在反向代理之后运行 Twenty 并遇到连接问题:
1. **验证 SERVER_URL:**
确保 `.env` 文件中的 `SERVER_URL` 与您的外部访问 URL 匹配,如果启用 SSL,请包含 `https`。
2. **检查反向代理设置:**
* 确认您的反向代理正确地将请求转发到 Twenty 服务器。
* 确保正确设置了像 `X-Forwarded-For` 和 `X-Forwarded-Proto` 这样的标头。
3. **重启服务:**
在进行更改后,重启反向代理和 Twenty 容器。
#### 上传图像时出错 - 权限被拒绝
将主机上的数据文件夹所有权从 root 切换到其他用户和组可以解决此问题。
#### 在工作流中测试 Logic 函数时出现“找不到文件”错误
在您的 twenty-server 容器中运行 `yarn command:prod application:rebuild-default-deps` 命令,以修复缺少依赖项的问题。
## 获取帮助
如果您遇到本指南未涵盖的问题:
* 检查日志:
查看容器日志以获取错误消息:
```bash
docker compose logs
```
* 社区支持:
联系 [Twenty 社区](https://github.com/twentyhq/twenty/issues) 或 [支持渠道](https://discord.gg/cx5n4Jzs57) 以获得帮助。

View File

@@ -0,0 +1,106 @@
---
title: 升级指南
icon: arrow-up-right-dots
---
## 通用指南
**在开始升级流程之前务必备份数据库**,运行:
```bash
docker exec -it {db_container_name_or_id} pg_dumpall -U {postgres_user} > databases_backup.sql
```
从备份恢复:
```bash
cat databases_backup.sql | docker exec -i {db_container_name_or_id} psql -U {postgres_user}
```
如果您使用 Docker Compose,请按照以下步骤操作:
1. 停止 Twenty:`docker compose down`
2. 在与 `docker-compose.yml` 同目录的 `.env` 文件中更改 `TAG` 值
3. 启动 Twenty:`docker compose up -d`
服务器在启动时会自动运行所有所需的升级迁移。 无需手动执行任何命令。
## 升级到 v2.34+ — 最低要求 PostgreSQL 15
Twenty v2.34 要求 PostgreSQL 15 或更高版本。 官方 Docker Compose 配置使用 PostgreSQL 16。 如果您的实例连接到外部托管的数据库,请在启动 v2.34 服务器之前对其进行升级。
## 跨版本升级(v1.23+)
自 **v1.23** 起,Twenty 支持跨版本升级。 您可以从任意受支持的版本直接跳到最新版本,而无需逐一经过每个中间版本。
例如,从 v1.23 直接升级到 v2.0 完全受支持。
## 升级到 v2.5+ — 静态数据加密信封
从 **v2.5** 开始,Twenty 会将静态存储的机密(OAuth 令牌、应用程序变量、签名密钥的私钥、敏感配置值、TOTP 机密)存储在带版本的 `enc:v2:` 加密信封中,并使用 `ENCRYPTION_KEY`(如果未设置 `ENCRYPTION_KEY`,则使用 `APP_SECRET`)进行加密。
在 v2.5 的首次启动时会运行较慢的升级命令,将现有行**回填**到新的加密信封中。 这些命令是幂等的——中断并重新启动服务器后会从上次停止的位置恢复——但在大型数据库上可能需要一段时间才能完成。 你可以使用 `upgrade:status` 来监控进度。
你应该在 v2.5 升级**之前**设置专用的 `ENCRYPTION_KEY`,这样回填从一开始就会在该密钥下写入行。 在回填完成后再更换密钥,则需要进行一次[轮换](/l/zh/developers/self-host/capabilities/key-rotation)。
## 轮换机密和签名密钥
对于日常运维任务,例如轮换 `ENCRYPTION_KEY`、轮换 JWT 签名密钥或吊销泄露的签名密钥,请参阅专门的[密钥轮换指南](/l/zh/developers/self-host/capabilities/key-rotation)。
## 检查升级状态
`upgrade:status` 命令可用于查看您的实例和工作区迁移的当前状态。 这在调试升级问题或提交支持请求时非常有用。
在服务器容器中运行:
```bash
docker exec -it {server_container_name_or_id} yarn command:prod upgrade:status
```
示例输出:
```sh
APP_VERSION: v1.23.0
Instance
Inferred version: 1.23.0
Latest command: 1.23.0_DropWorkspaceVersionColumnFastInstanceCommand_1785000000000
Status: Up to date
Executed by: v1.23.0
At: 2026-04-16T11:43:58.823Z
Workspace
Apple (20202020-1c25-4d02-bf25-6aeccf7ea419)
Inferred version: 1.23.0
Latest command: 1.23.0_UpdateGlobalObjectContextCommandMenuItemsCommand_1780000005000
Status: Up to date
Executed by: v1.23.0
At: 2026-04-16T11:44:09.361Z
Summary
Instance: Up to date
Workspaces: 1 up to date, 0 behind, 0 failed (1 total)
```
### 选项
| 标志 | 描述 |
| ------------------------- | ----------------------- |
| `-w, --workspace-id <id>` | 筛选特定工作区。 可多次传递。 |
| `-f, --failed-only` | 隐藏已是最新的工作区,仅显示落后和失败的条目。 |
## 故障排除
如果某些工作区的升级失败,服务器将不会越过失败的步骤继续进行。 重启服务器(`docker compose up -d`)将从中断处重试升级。
要快速定位问题,运行:
```bash
docker exec -it {server_container_name_or_id} yarn command:prod upgrade:status --failed-only
```
这将仅显示落后或失败的工作区,并附上每个失败的错误信息。
## v1.23 之前
如果您的实例早于 v1.23,您必须按顺序逐步升级经过每个主要标记版本(从 v1.6 到 v1.7,再从 v1.7 到 v1.8,依此类推),直到达到 v1.23。 届时,您可以直接跳到最新版本。