feat: expand companion platform, device controls, and memoir workflows
ci / verify (push) Canceled after 0s
ci / verify (push) Canceled after 0s
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
services:
|
||||
web:
|
||||
image: data-terminal-cloud-web:0.96.3-rc.admin-ui2
|
||||
@@ -0,0 +1,10 @@
|
||||
# Add after the production overlays. One API instance owns the embedded broker.
|
||||
services:
|
||||
api:
|
||||
ports:
|
||||
- "1883:1883"
|
||||
environment:
|
||||
DEVICE_MQTT_PUBLIC_URL: mqtt://${PUBLIC_HOST}:1883
|
||||
DEVICE_MQTT_ADDRESS: ":1883"
|
||||
web:
|
||||
image: data-terminal-cloud-web:${PLATFORM_BUILD_VERSION}
|
||||
@@ -1,9 +1,28 @@
|
||||
# Add after compose.override.yaml and the server's existing compose.subtitle.yaml.
|
||||
x-onboarding-runtime: &onboarding-runtime
|
||||
DIRECT_CHAT_TEMPLATE_FILE: /run/secrets/voice-runtime/voice-chat-template.json
|
||||
VOLC_ACCESS_KEY_ID: ""
|
||||
VOLC_ACCESS_KEY_ID_FILE: /run/secrets/voice-runtime/volc-access-key-id
|
||||
VOLC_SECRET_ACCESS_KEY: ""
|
||||
VOLC_SECRET_ACCESS_KEY_FILE: /run/secrets/voice-runtime/volc-secret-access-key
|
||||
ONBOARDING_ENABLED: ${ONBOARDING_ENABLED:-true}
|
||||
ONBOARDING_ACTIVATION_ENABLED: ${ONBOARDING_ACTIVATION_ENABLED:-true}
|
||||
ONBOARDING_PAUSE_CLAIMS: ${ONBOARDING_PAUSE_CLAIMS:-false}
|
||||
ONBOARDING_SMS_LOGIN_ENABLED: ${ONBOARDING_SMS_LOGIN_ENABLED:-false}
|
||||
ONBOARDING_SAAS_CAPTCHA_DISABLED: ${ONBOARDING_SAAS_CAPTCHA_DISABLED:-false}
|
||||
ONBOARDING_SMS_PROVIDER: ${ONBOARDING_SMS_PROVIDER:-gateway}
|
||||
TENCENT_SMS_SECRET_ID: ""
|
||||
TENCENT_SMS_CONFIG_FILE: ${TENCENT_SMS_CONFIG_FILE:-}
|
||||
TENCENT_CAPTCHA_CONFIG_FILE: ${TENCENT_CAPTCHA_CONFIG_FILE:-}
|
||||
TENCENT_SMS_SECRET_ID_FILE: ${TENCENT_SMS_SECRET_ID_FILE:-}
|
||||
TENCENT_SMS_SECRET_KEY: ""
|
||||
TENCENT_SMS_SECRET_KEY_FILE: ${TENCENT_SMS_SECRET_KEY_FILE:-}
|
||||
TENCENT_SMS_SDK_APP_ID: ${TENCENT_SMS_SDK_APP_ID:-}
|
||||
TENCENT_SMS_SIGN_NAME: ${TENCENT_SMS_SIGN_NAME:-}
|
||||
TENCENT_SMS_TEMPLATE_ID: ${TENCENT_SMS_TEMPLATE_ID:-}
|
||||
WECHAT_MINI_APP_ID: ${WECHAT_MINI_APP_ID:-wx4553119e05f11660}
|
||||
WECHAT_MINI_APP_SECRET: ""
|
||||
WECHAT_MINI_APP_SECRET_FILE: ${WECHAT_MINI_APP_SECRET_FILE:-}
|
||||
ONBOARDING_ALLOW_LOCAL_HTTP: "false"
|
||||
ONBOARDING_MASTER_KEY: ""
|
||||
ONBOARDING_MASTER_KEY_FILE: /run/secrets/voice-runtime/onboarding-master-key
|
||||
@@ -20,6 +39,12 @@ x-onboarding-runtime: &onboarding-runtime
|
||||
VOLC_HARDWARE_DEVICE_CREDENTIAL_MASTER_KEY: ${VOLC_HARDWARE_DEVICE_CREDENTIAL_MASTER_KEY}
|
||||
|
||||
services:
|
||||
callbacks:
|
||||
image: data-terminal-cloud-backend:${ONBOARDING_RELEASE_VERSION:?set release version}
|
||||
environment:
|
||||
ONBOARDING_ENABLED: "false"
|
||||
ONBOARDING_ACTIVATION_ENABLED: "false"
|
||||
ONBOARDING_SMS_LOGIN_ENABLED: "false"
|
||||
api:
|
||||
image: data-terminal-cloud-backend:${ONBOARDING_RELEASE_VERSION:?set release version}
|
||||
environment:
|
||||
|
||||
@@ -17,6 +17,7 @@ x-server-backend-environment: &server-backend-environment
|
||||
OBJECT_STORE_REGION: us-east-1
|
||||
OBJECT_STORE_SECURE: "false"
|
||||
OBJECT_STORE_PUBLIC_SECURE: "true"
|
||||
FIRMWARE_DOWNLOAD_BASE_URL: ${PUBLIC_ORIGIN}
|
||||
CURSOR_SIGNING_SECRET: ${CURSOR_SIGNING_SECRET}
|
||||
SHARE_TOKEN_SIGNING_SECRET: ${SHARE_TOKEN_SIGNING_SECRET}
|
||||
MEMORY_TOOL_BASE_URL: ${PUBLIC_ORIGIN}/internal/v1/tools/memory-search
|
||||
@@ -204,6 +205,7 @@ services:
|
||||
volumes:
|
||||
- ./deploy/server/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||||
- /var/www/acme:/var/www/acme:ro
|
||||
depends_on:
|
||||
- api
|
||||
- callbacks
|
||||
|
||||
@@ -20,7 +20,7 @@ alert_webhook_url=${ALERT_WEBHOOK_URL:-}
|
||||
alert_webhook_secret_file=${ALERT_WEBHOOK_SECRET_FILE:-/etc/data-terminal-cloud/monitor-webhook-secret}
|
||||
platform_health_report_url=${PLATFORM_HEALTH_REPORT_URL:-}
|
||||
platform_health_report_secret_file=${PLATFORM_HEALTH_REPORT_SECRET_FILE:-/etc/data-terminal-cloud/platform-health-callback-secret}
|
||||
expected_public_tcp_ports=${EXPECTED_PUBLIC_TCP_PORTS:-22,80,443}
|
||||
expected_public_tcp_ports=${EXPECTED_PUBLIC_TCP_PORTS:-22,80,443,1883}
|
||||
deployment_profile=${HOST_DEPLOYMENT_PROFILE:-demo}
|
||||
if [[ -f "$offsite_config_file" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
server {
|
||||
listen 80;
|
||||
location ^~ /.well-known/acme-challenge/ { root /var/www/acme; }
|
||||
server_name _;
|
||||
# First-boot clock bootstrap only. The response is authenticated by TIME1.
|
||||
location = /api/v1/device/time-challenges {
|
||||
@@ -14,18 +15,18 @@ server {
|
||||
proxy_buffering off;
|
||||
}
|
||||
location / {
|
||||
return 301 https://121.41.46.238$request_uri;
|
||||
return 301 https://82.157.201.114$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name 121.41.46.238;
|
||||
server_name 82.157.201.114;
|
||||
server_tokens off;
|
||||
client_max_body_size 256m;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/121.41.46.238/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/121.41.46.238/privkey.pem;
|
||||
ssl_certificate /etc/letsencrypt/live/82.157.201.114/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/82.157.201.114/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 1d;
|
||||
@@ -58,6 +59,15 @@ server {
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location /f/ {
|
||||
proxy_pass $api_backend;
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_read_timeout 15m;
|
||||
send_timeout 15m;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# The voice provider can call only this signed, conversation-scoped tool.
|
||||
# Do not expose the rest of the /internal namespace.
|
||||
location = /internal/v1/tools/memory-search {
|
||||
@@ -85,6 +95,30 @@ server {
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# Dify workflow console; authenticated by its own console session.
|
||||
location = /dify { return 302 /apps; }
|
||||
# Keep Dify session refresh separate from the platform OIDC callback.
|
||||
location = /auth/refresh {
|
||||
proxy_pass http://story-dify-nginx:80;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 900s;
|
||||
}
|
||||
location ~ ^/(?:apps|app|signin|init|install|reset-password|activate|datasets|tools|plugins|explore|snippets|agents|_next|logo|images|vs|marketplace|in-site-message|screenshots|education)(?:/|$) {
|
||||
proxy_pass http://story-dify-nginx:80;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 900s;
|
||||
}
|
||||
location ^~ /console/api {
|
||||
proxy_pass http://story-dify-nginx:80;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 900s;
|
||||
}
|
||||
location ^~ /v1/ {
|
||||
proxy_pass http://story-dify-nginx:80;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 900s;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass $web_backend;
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/tencent-captcha.json
|
||||
@@ -0,0 +1,18 @@
|
||||
# 腾讯云人机验证码:一个 JSON 文件
|
||||
|
||||
填写 `tencent-captcha.json.example` 并另存为 `tencent-captcha.json`,不要提交填写后的文件,不要发到聊天里。
|
||||
|
||||
- `secret_id`、`secret_key`:腾讯云 API 访问密钥,需要验证码票据校验权限。可以使用已有密钥,但仅有短信权限的子账号密钥需要增加验证码权限;建议独立最小权限密钥。
|
||||
- `saas.captcha_app_id`、`saas.app_secret_key`:在腾讯云验证码控制台创建 **Web/App** 类型的验证码,填入其 CaptchaAppId、AppSecretKey。
|
||||
- `mini_program.captcha_app_id`、`mini_program.app_secret_key`:单独创建 **微信小程序** 类型的验证码,填入另一组。不是微信小程序自身的 AppID/Secret,也不是短信 SDKAppID。
|
||||
- 两端不能填同一个 CaptchaAppId;暂不使用的一端两个字段都留空。所有字段使用字符串,保留双引号。
|
||||
|
||||
文件上传到服务器 `/etc/data-terminal-cloud/voice-runtime/tencent-captcha.json`。该目录已有只读挂载,容器内默认读取 `/run/secrets/voice-runtime/tencent-captcha.json`,无须修改短信配置。权限设为 `root:65532`、`640`,重建/重启 api 和 worker 读取文件。
|
||||
|
||||
部署含迁移 71 的版本后,管理端 → 运行配置 → 验证码设置,分别选择 SaaS 或微信小程序的「现有图形验证码 / 腾讯云验证码」并保存。此配置全平台生效,仅 `ops_admin` 可操作。默认为图形验证码;配置文件本身不会启用腾讯云。页面显示「配置已加载」只说明字段完整,不代表已联网核验密钥、权限或套餐。
|
||||
|
||||
微信小程序还需在微信公众平台「设置 → 第三方设置 → 添加插件」授权 **腾讯验证码**,插件 provider `wx1fe8d9a3cb067a75`,代码使用版本 `2.1.5`。授权后用微信开发者工具重新编译、真机测试并发布小程序;后端发布不会自动发布小程序。
|
||||
|
||||
腾讯云控制台选择滑动拼图验证,填写对应的网站域名/小程序配置。当前未接入可选的 CaptchaAppId 加密鉴权,因此不要开启「CaptchaAppId 强制校验」。验证码套餐费用与短信费用独立。SDK/插件失败、云端拒绝或超时都不放行,也不自动退回图形验证;可由管理员主动切回图形模式。
|
||||
|
||||
参考:[Web](https://cloud.tencent.com/document/product/1110/36841)、[微信小程序](https://cloud.tencent.com/document/product/1110/49319)、[服务端票据校验](https://cloud.tencent.com/document/product/1110/75490)。
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"secret_id": "",
|
||||
"secret_key": "",
|
||||
"saas": {
|
||||
"captcha_app_id": "",
|
||||
"app_secret_key": ""
|
||||
},
|
||||
"mini_program": {
|
||||
"captcha_app_id": "",
|
||||
"app_secret_key": ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
tencent-sms.env
|
||||
tencent-sms-secret-id
|
||||
tencent-sms-secret-key
|
||||
tencent-sms.json
|
||||
@@ -0,0 +1,53 @@
|
||||
# 腾讯云短信单文件配置
|
||||
|
||||
只需填写 `tencent-sms.json.example` 中的所有占位文字,另存为 `tencent-sms.json`,上传到:
|
||||
|
||||
`/etc/data-terminal-cloud/voice-runtime/tencent-sms.json`
|
||||
|
||||
`templates.login` 填登录模板 ID,`templates.register` 填注册模板 ID,`templates.change_password` 填修改密码模板 ID,`templates.change_phone` 填更换手机号模板 ID。其他字段填写 SecretId、SecretKey、短信 SDK AppID 和签名名称;保留英文双引号。AppKey 不用填。
|
||||
|
||||
更新服务端并应用 `000070_sms_purpose` 迁移后,API 和 worker 重启时会自动读取该文件。无需再拆分密钥或补充其他短信环境变量。文件中的 `enabled` 为 `true` 时开启短信,为 `false` 时关闭;单文件中的短信设置优先于旧版逐项配置,其他业务配置不变。
|
||||
|
||||
默认发送一个变量:6 位验证码。已核对当前腾讯云注册模板需要“验证码、有效分钟数”两个变量,单文件的 `template_params.register` 因此设置为 `["code", "expires_minutes"]`,实际发送验证码和 `5`。这部分无需填写真实值,由程序生成;其他三个模板保持默认单变量。
|
||||
|
||||
注册/登录共用的入口自动按账号是否已有手机号凭据选择模板,“忘记密码”使用修改密码模板。更换手机号的模板配置和按用途发送能力已支持,但项目目前尚无换号业务接口和页面,登录接口不会接受换号用途。
|
||||
|
||||
保存为 UTF-8(支持 Windows 编辑器的 BOM),文件访问权限沿用服务器同目录现有密钥文件,保证 API 和 worker 可以读取。填写后的 `tencent-sms.json` 已被本目录 `.gitignore` 忽略。
|
||||
|
||||
## 以下为旧版分文件配置,仅供兼容;使用上面的单文件时无需填写
|
||||
|
||||
共需填写 5 项:短信 SDK AppID、审核通过的签名名称、验证码模板 ID、SecretId、SecretKey。现有 AppKey 不需要填写。SaaS 和小程序共用同一套服务端配置。
|
||||
|
||||
## 1. 复制并填写文件
|
||||
|
||||
保留 `.example` 文件作为空白模板,复制一份并去掉文件名末尾的 `.example`:
|
||||
|
||||
| 填好后的文件名 | 需要填写的内容 |
|
||||
| --- | --- |
|
||||
| `tencent-sms.env` | 前 3 个配置项:短信 SDK AppID、签名名称、模板 ID |
|
||||
| `tencent-sms-secret-id` | 仅一行 SecretId,替换原占位文字 |
|
||||
| `tencent-sms-secret-key` | 仅一行 SecretKey,替换原占位文字 |
|
||||
|
||||
两个密钥文件不要写 `SecretId=` 或 `SecretKey=`,不要加引号、注释或其他说明。保存为 UTF-8 无 BOM;Windows 下注意文件名不要被自动加上 `.txt`。
|
||||
|
||||
短信 SDK AppID 来自腾讯云短信控制台,不是微信小程序的 `wx...` AppID。签名填写名称,不填写签名 ID。当前短信模板应只有一个变量,用于 6 位验证码,例如“您的验证码为 {1},5 分钟内有效”。
|
||||
|
||||
## 2. 上传到服务器
|
||||
|
||||
| 本地填写好的文件 | 服务器保存路径 |
|
||||
| --- | --- |
|
||||
| `tencent-sms-secret-id` | `/etc/data-terminal-cloud/voice-runtime/tencent-sms-secret-id` |
|
||||
| `tencent-sms-secret-key` | `/etc/data-terminal-cloud/voice-runtime/tencent-sms-secret-key` |
|
||||
| `tencent-sms.env` | `/etc/data-terminal-cloud/tencent-sms.env`(配置备份) |
|
||||
|
||||
项目现有 Compose 把服务器 `/etc/data-terminal-cloud/voice-runtime` 只读挂载到容器 `/run/secrets/voice-runtime`,所以 `.env` 模板中的两个路径不用改。
|
||||
|
||||
## 3. 接入现有部署配置
|
||||
|
||||
把 `tencent-sms.env` 中的配置项合并到服务器部署当前使用的 `.env` 文件;同名项更新原值,不要重复添加,也不要用本模板覆盖整份 `.env`。保留数据库、站点地址、原有主密钥等其他配置。
|
||||
|
||||
填写全部参数、上传两个密钥文件,并更新服务端版本后,把 `ONBOARDING_SMS_LOGIN_ENABLED` 改成 `true`。使用现有的完整 Compose 部署命令重新创建 `api` 和 `worker`,使环境变量生效;部署配置需包含项目的 `compose.onboarding.yaml`。仅上传文件或普通重启容器不会自动加载新的环境变量。
|
||||
|
||||
文件访问权限沿用同目录现有密钥文件的属主、属组和权限,确保 API 与 worker 运行用户可以读取,其他无关用户不能读取。填好后的密钥文件仅存服务端,不放进小程序或前端代码。此目录的 `.gitignore` 已忽略去掉 `.example` 后的三个文件。
|
||||
|
||||
上传完成后,可以只告知文件所在路径,后续检查无需在聊天里粘贴密钥内容。
|
||||
@@ -0,0 +1 @@
|
||||
填写你的SecretId
|
||||
@@ -0,0 +1 @@
|
||||
填写你的SecretKey
|
||||
@@ -0,0 +1,15 @@
|
||||
# 腾讯云短信配置模板(UTF-8 编码)
|
||||
# SaaS 和小程序共用这份服务端配置。
|
||||
# 请填写下面 3 项;SDK AppID 是短信应用 ID,不是微信小程序 AppID。
|
||||
TENCENT_SMS_SDK_APP_ID=填写短信SDKAppID
|
||||
TENCENT_SMS_SIGN_NAME='填写审核通过的短信签名名称'
|
||||
TENCENT_SMS_TEMPLATE_ID=填写审核通过的验证码模板ID
|
||||
|
||||
# SecretId、SecretKey 分别填写在随附的两个密钥文件中。
|
||||
# 以下为容器内路径,已对应项目现有的服务器目录挂载。
|
||||
TENCENT_SMS_SECRET_ID_FILE=/run/secrets/voice-runtime/tencent-sms-secret-id
|
||||
TENCENT_SMS_SECRET_KEY_FILE=/run/secrets/voice-runtime/tencent-sms-secret-key
|
||||
ONBOARDING_SMS_PROVIDER=tencent
|
||||
|
||||
# 所有参数和密钥文件配置完成,且服务端已更新后,改为 true。
|
||||
ONBOARDING_SMS_LOGIN_ENABLED=false
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"enabled": true,
|
||||
"secret_id": "填写SecretId",
|
||||
"secret_key": "填写SecretKey",
|
||||
"sdk_app_id": "填写短信SDKAppID",
|
||||
"sign_name": "填写审核通过的短信签名名称",
|
||||
"templates": {
|
||||
"login": "填写登录模板ID",
|
||||
"register": "填写注册模板ID",
|
||||
"change_password": "填写修改密码模板ID",
|
||||
"change_phone": "填写更换手机号模板ID"
|
||||
},
|
||||
"template_params": {
|
||||
"register": ["code", "expires_minutes"]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user