# Data Twin Backend **Repository Path**: jasonbu163/data-twin-backend ## Basic Information - **Project Name**: Data Twin Backend - **Description**: Data Twin Backend:一个专注于数据孪生技术的后端开发平台,提供高效、可靠的API服务,支持实时数据同步与分析,助力开发者快速构建智能应用。 - **Primary Language**: Python - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-27 - **Last Updated**: 2026-09-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Data Twin Platform ## 开发者数据库维护工具 [随源码使用的数据库维护工具](backend/scripts/database_maintenance/README.zh-CN.md) 配合 Alembic,提供离线策略更新及范围内 MSSQL 数据导出、清空、初始化与恢复。详见[完整开发手册](docs/DATABASE_MAINTENANCE.zh-CN.md),包括 policy 配置和共享库保护;不是常规部署步骤,不接入 TSS 帮助中心。 DTB-070 新增固定 JSON 策略、按存储日期比较、预览优先的人工 `prune` 历史清理。完整九步教程见上述手册第 11 节;不含自动调度或容量告警,真实目标删除仍需单独授权。 ## TSS 可编辑帮助(DTB-054) TSS 帮助中心与页面 `?` 共用六栏目、42 篇双语文章。[内容合同](docs/help/CONTENT_CONTRACT.zh-CN.md)及其链接章节是唯一人工正文源。执行 `pnpm --dir twin-state-studio run help:build` 生成两端资源,执行 `pnpm --dir twin-state-studio run help:check` 检查漂移。两份生成 JSON 配套交付,禁止手工修改生成正文。backend Docker 已复制整个 backend 目录,包含只读帮助资源。 当前连接 backend 在 MSSQL 保存现场覆盖及不可变历史。核对目标与备份后按常规 Alembic 流程升级;已跨过旧部件归属迁移的数据库,不为帮助新迁移重跑历史归属工具。应用升级保留现场编辑。详见 [TSS 指南](twin-state-studio/README.zh-CN.md)与 [API 合同](backend/API_CONTRACT.zh-CN.md)。离线明确显示随包基础版本,不宣称同步了现场版本。 从 Blender 制作、GLB 接入到现场联调与部署,按[模型到部署总 SOP](docs/MODEL_TO_DEPLOYMENT_SOP.zh-CN.md)进入;专题操作正文统一由该手册链接。 > **旧库升级必读:** 有旧 `devices` 行且首次跨过 0035 时,先按[设备部件迁移手册](docs/DEVICE_PART_MIGRATION.zh-CN.md)逐行确认归属,再用工具 Apply(当前固定到 0036)。空库可正常 `upgrade head`;跨过 0035 后恢复常规升级,未来迁移 gate 另计。下文通用升级命令均受此条件约束。 本仓库包含 FastAPI/MSSQL 后端、Twin State Studio 与唯一 Vue/Vite JavaScript 前端。`frontend-js` 在同一运行时中承载生产 Dashboard 和现场适配工程工具。 ## 场景适配长期方向 长期目标是在不为每个现场重新编写前端行为代码的前提下,把符合既定命名与动画合同的 GLB 场景适配为可运行的数字孪生效果:建模/资产整理负责提供静态状态组、预制 `__action` 代理节点和具名 clip;现场适配前端负责编辑状态、显隐、动作、条件、运动和资源锁 Mapping;后端控制面负责版本化草稿、审查、发布与唯一 active version。发布会在 version 上冻结 `runtime_mapping_document_json`,同源虚拟 Mapping URL 会把该 active document raw-return 给 Runtime。Dashboard 与 Site Adaptation 只执行显式加载并已 pin 的激活版本,业务状态仍由后端和 `device_states` 等事实源决定。 这是一条“配置化、低/零代码现场适配”路线,而不是宣称任意 GLB 无需合同即可自动运行,也不绕过发布、回退、权限或安全恢复门禁。每项新增动作语义、Runtime 能力和编辑器能力仍通过独立、受限任务演进和验证。 文档入口:[docs 使用说明](docs/README.zh-CN.md)。路线图入口:[TSS Mapping 路线图](docs/TSS_MAPPING_REFACTOR_ROADMAP.md) · [场景适配 Runtime 路线图](docs/SCENE_ADAPTATION_RUNTIME_ROADMAP.zh-CN.md)。 ## 目录结构 ```text backend/ FastAPI、SQLAlchemy、Alembic、SQL Server 接入 app/ API 路由、领域 Service、Schema 和数据库模型 config/ 设备显示名等经复核的后端配置 docker/sqlserver/ SQL Server 镜像、入口、健康检查和建库脚本 Dockerfile.prod 生产 backend 镜像定义(dev Compose 通过 reload 覆盖命令复用) scripts/ 显式 migration 辅助、seed 和诊断 CLI frontend-js/ Dashboard 与 Site Adaptation 唯一的 Vue 3 + Element Plus + Three.js owner src/app/dashboard/ 生产 Dashboard src/app/site-adaptation/ 现场适配工程工具 src/core/twin-runtime/ 共享模型/状态/recipe/interaction 运行时与 catalog public/runtime-assets/models/ 运行时 GLB 模型资产 twin-state-studio/ 独立 Tauri 数据库与 HTTP/WebSocket 诊断工具 tools/ 项目级资产、转换、血缘和复核工具 docs/ 部署排查手册、架构说明和设计文档 plans/ 根任务 bundle 与三文件任务记录 demo/ Wis3D/演示参考包和本地解压示例 output/ 被忽略的本地截图和生成证据,不是运行时源码 docker-compose.dev.yml 全容器热更新栈:frontend-js + backend + MSSQL docker-compose.mssql.yml 只运行 MSSQL,backend 和前端使用宿主机源码 docker-compose.prod.yml 生产式单机部署:backend + model-resource-manager + Nginx docker/nginx/ 生产 Nginx 代理和 runtime-config 模板 ``` `docker-compose.dev.yml` 与 `docker-compose.mssql.yml` 是互斥场景:二者都使用 `mssql` 与宿主机端口 `14333`。`docker-compose.dev.yml` 精确启动 `sqlserver`、`backend`、`frontend-js`;`docker-compose.mssql.yml` 只启动数据库,backend 和前端在宿主机运行。`docker-compose.prod.yml` 启动镜像内 backend、常驻的 `model-resource-manager` 和 Nginx,MSSQL 由外部提供;在宿主机 backend 已释放 `8144` 后,它可以刻意把 database-only SQL Server 作为 external database 复用。仓库根目录不使用 `.env`;生产端点可选使用 `BACKEND_PUBLIC_URL`、`PROD_HTTP_PORT` 和 `BACKEND_HTTP_PORT` 三个 Compose 变量。 环境变量按运行位置拆分: ```text backend/.env docker-compose.mssql.yml + 宿主机 backend,MSSQL_HOST=localhost backend/.env.dev.docker docker-compose.dev.yml 全容器 dev 联调,MSSQL_HOST=sqlserver backend/.env.prod.docker 生产 backend 容器,访问宿主机或外部 MSSQL ``` 规则:`docker-compose.mssql.yml` 是唯一读取 `backend/.env` 的 Compose,它只把该文件用于 MSSQL 初始化,宿主机 backend 读取同一文件连接 `localhost:14333`。dev 和 prod Compose 分别只读取自己的 Docker env 文件。 项目级工具统一放在 `tools/`,具体约定见 [tools/README.zh-CN.md](tools/README.zh-CN.md)。数据处理类工具默认使用自身目录下的 `inputs/` / `outputs/` 管理输入输出;需要生成运行时代码时,必须在工具 README 中说明例外。 ## 当前后端能力 后端升级计划已经完成并内化到 [backend/README.zh-CN.md](backend/README.zh-CN.md)。当前后端提供: - `devices`:以 `(deviceId, partId)` 联合身份保存部件资料与卡片;点击打开目标设备聚合卡片,再按部件读取资料。旧 device-only 请求遇到多部件返回 `409 DEVICE_PART_REQUIRED`。 - `device_labels`:设备多语言显示名表,由 `backend/config/device_labels.yml` 在后端启动时幂等同步;接口按 `locale` 或 `Accept-Language` 返回当前语言的 `deviceName`。 - `device_states`:数字孪生部件级渲染状态表,身份为 `sceneCode + deviceId + partId`。 - HTTP snapshot:`GET /api/digital-twin/scenes/main/models`。 - WebSocket 实时流:`WS /ws/digital-twin/scenes/main/models`,首包 snapshot,后续 changed。 - `collection_facts` / `collection_fact_projection_cursors`:当前 TSS 唯一 producer 交换面与 per-Service Mapping 进度;第三方写入者或逐点 Simulation 更新 facts,API-first Mapping 每周期新读绑定事实并调用目标 API;legacy 连续投影已封存,源码待 TSS-018 清理。 - DTB-022 已删除经核验为空的退役 `tss_flows`、`tss_flow_steps`、`tss_twin_incremental_facts`、`tss_twin_current_facts` 与 `tss_twin_projection_cursors` 表;原 migration 仅保留为历史。 - backend Simulation API、Celery/Redis worker、TSS direct-write executor 与旧双事实 runtime 已退役;`tss_twin_temperature_history` 仍是现役 Service target。 当前 TSS 到前端的链路为:第三方写入者或逐点 Simulation -> `collection_facts` -> 定时 API-first Mapping Runtime -> 配置的目标 API -> backend WebSocket -> Dashboard/Site Adaptation。TSS 一级工作区精确为“数据工作区”“连接与诊断”“帮助中心”;Flow 不再是现役工作区、command、executor、repository 或 fallback。 前后端 API 契约已单独沉淀: ```text backend/API_CONTRACT.zh-CN.md backend/API_CONTRACT.md ``` 这两份文档用于前端和 AI 辅助开发,重点说明统一响应、`deviceId + partId + positionKey`、设备显示名国际化、HTTP snapshot、WebSocket 合并规则和已退役 Simulation endpoint 边界。 ## 计划入口 根计划使用 [PLAN.zh-CN.md](PLAN.zh-CN.md) 作为当前任务索引,具体任务进入 `plans//spec.md`、`tasks.md`、`checklist.md`。前端计划统一由 [frontend-js/PLAN.zh-CN.md](frontend-js/PLAN.zh-CN.md) 承载;迁移后的 FD/FS/TR 历史 bundle 位于 `frontend-js/plans/`。 核心命名契约: ```text 静态节点 {deviceId}__{partId}--{stateKey} 状态流转动画 {deviceId}__{partId}:{fromState}_{toState} 动态代理节点 {deviceId}__action ``` ## 推荐运行方式 | Compose | 启动内容 | 代码运行位置 | 使用场景 | 环境文件 | | --- | --- | --- | --- | --- | | 无 | backend + frontend-js 进程 | 宿主机源码 | 连接已有 SQL Server 的源码开发 | `backend/.env` | | `docker-compose.dev.yml` | MSSQL + backend + frontend-js | 全部在容器中,源码 bind mount | 日常全栈联调、热更新 | `backend/.env.dev.docker` | | `docker-compose.mssql.yml` | 仅 MSSQL | backend 和前端在宿主机源码运行 | 本地 IDE 调试、直接使用宿主机工具链 | `backend/.env` | | `docker-compose.prod.yml` | backend + `model-resource-manager` + Nginx | Nginx 提供 `frontend-js/dist`,backend 和常驻模型管理器使用镜像 | 生产式部署,连接宿主机或外部 MSSQL | `backend/.env.prod.docker` | database-only 与全 Docker dev 不得同时运行;在这两个场景之间切换前,先使用对应 compose 的 `down` 停止当前入口。不要添加 `-v`,否则会删除持久化数据库 volume。production Compose 可以刻意复用 database-only 作为 external database;这是独立、显式配置的拓扑,不是共享 Compose project。人工测试前请先读 [Compose 验证 SOP](docs/COMPOSE_VALIDATION_SOP.zh-CN.md)。 三份 Compose 的 project name 分别是:`data-twin-dev`、`data-twin-database-only`、`data-twin-prod`。 数据库 volume 按场景隔离:全容器 dev 使用 `data-twin-dev-volume`,MSSQL-only 使用 `data-twin-database-only-volume`。生产 Compose 不定义数据库 volume,因为 `docker-compose.prod.yml` 连接的是外部 SQL Server。 部署与排查手册:[中文](docs/DEPLOYMENT_TROUBLESHOOTING.zh-CN.md) · [English](docs/DEPLOYMENT_TROUBLESHOOTING.md) 命令平台标记:`bash` 代码块用于 Linux/macOS 终端,`powershell` 代码块用于 Windows PowerShell 5.1/7。Docker Compose、`pnpm` 和 `uv` 的主体命令相同;复制 env、切换目录、设置临时变量和生成日期时,请使用代码块中对应平台的写法。 ### 宿主机 backend 依赖 `docker-compose.mssql.yml` 与“本地进程”模式会在宿主机运行 backend。首次 clone,或 `backend/pyproject.toml` / `backend/uv.lock` 发生变化后,在仓库根目录执行: ```bash cd backend uv sync --locked cd .. ``` Windows 的 `tzdata` 已按平台写入 backend 依赖并锁定,用于让 `zoneinfo` 解析 `Asia/Shanghai`。不要把时区改成 Windows 本地名称,也不需要给 `Asia/Shanghai` 加双引号。`MSSQL_DRIVER` 必须与宿主机已安装的 ODBC 驱动名称完全一致(Win10 常见 Driver 17,Win11 可为 Driver 18);Docker backend 镜像固定安装 Driver 18。只运行全容器 dev 或生产 Compose 时,镜像构建会按 lockfile 安装 backend 依赖,无需在宿主机另行执行 `uv add tzdata`。 ### 全容器调试环境 首次运行先准备环境变量: ```bash cp backend/.env.dev.docker.example backend/.env.dev.docker ``` 在 `backend/.env.dev.docker` 中填写 SQL Server 密码后,先只启动数据库: ```bash docker compose -f docker-compose.dev.yml up -d --build sqlserver ``` `docker-compose.dev.yml` 不会在镜像构建或 backend 启动时自动执行 Alembic、seed 或建表。首次初始化/升级数据库时,使用宿主机 backend 源码环境显式执行: 执行前核对维护 CLI 实际解析的 MSSQL 目标:当 `DATABASE_CONFIG_ENABLED=true` 且 SQLite 有完整记录时,保存配置优先于 `.env`;只改 `.env` 不能保证命中 dev 数据库。dev Docker 的 false 不会自动传给宿主机 CLI。先确认保存配置、目标与 backend 重启状态;旧库跨 0035 还须遵循文首迁移手册。 ```bash cd backend cp .env.example .env # .env 指向同一个 dev SQL Server:MSSQL_HOST=localhost、MSSQL_HOST_PORT=14333;密码与 .env.dev.docker 使用同一个值 uv sync --locked uv run alembic upgrade head uv run python scripts/seed_devices.py cd .. docker compose -f docker-compose.dev.yml up -d backend frontend-js ``` 如果数据库已经初始化过,可直接启动 backend 和前端;只有 migration 或开发基线数据确实需要更新时才重复执行上面的维护命令。 停止完整开发栈: ```bash docker compose -f docker-compose.dev.yml down ``` 默认地址: ```text 前端 Dashboard: http://127.0.0.1:5178/ 现场适配: http://127.0.0.1:5178/site-adaptation/runtime-connection Backend: http://127.0.0.1:8144 ``` 调试栈行为: - backend 映射 `backend/` 源码并使用 Uvicorn reload,Python 源码修改会自动生效。 - `frontend-js/` 映射到 `/workspace/frontend-js`,一个 Vite 进程通过 HMR 服务全部路由;GLB 修改后刷新即可。 - Dockerfile 构建阶段和普通 backend 服务启动阶段都不写入数据库;schema migration、设备 seed 和 Dashboard 样例 seed 都是显式维护动作。 - 普通前端优化不要反复 build;只有 Dockerfile、依赖、挂载或端口变化后才 build/recreate `frontend-js`。 - 前端 dev 镜像默认使用 `docker.m.daocloud.io/library/node:22-alpine` 和 `https://registry.npmjs.org`;现场有其他镜像源时可覆盖 `FRONTEND_NODE_IMAGE` 和 `NPM_REGISTRY` build args。 ### 生产 Compose(backend + model-resource-manager + Nginx) 当前端已经构建到 `frontend-js/dist`、backend 使用镜像运行、MSSQL 在 Compose 外部提供时,使用这个入口: 本机 production-style 验证若复用 database-only,必须先启动 `docker-compose.mssql.yml` 并等待 `mssql` 健康;production Compose 自身不会启动 SQL Server。 ```bash cp backend/.env.prod.docker.example backend/.env.prod.docker pnpm --dir frontend-js install --frozen-lockfile pnpm --dir frontend-js run build docker compose -f docker-compose.prod.yml config --quiet docker compose -f docker-compose.prod.yml up -d --build docker compose -f docker-compose.prod.yml ps ``` `docker-compose.prod.yml` 精确启动三个服务:`backend`、`model-resource-manager` 和 `nginx`。Compose 先等待 backend 健康,再等待 manager 健康,最后才启动 Nginx。manager 拥有可写模型目录 mount,但自身没有发布宿主机端口;Nginx 只在 `127.0.0.1:8181` 暴露本机操作员路由。Nginx 读取宿主机映射的 `frontend-js/dist`,把 `/api/` 和 `/ws/` 代理到 `backend:8144`,并提供同源 `/runtime-config`。backend 同时发布宿主机 `BACKEND_HTTP_PORT`(默认 `8144`),供二次开发客户端直接访问 API 及 `/docs`、`/redoc`、`/openapi.json`;Nginx 端点仍是前端使用的网关。生产 backend 镜像由 `backend/Dockerfile.prod` 构建,数据库参数读取 `backend/.env.prod.docker`。容器内的 `localhost` 指向 backend 容器自己;访问 Docker Desktop 暴露在宿主机上的 SQL Server 使用 `MSSQL_HOST=host.docker.internal`,访问外部 SQL Server 则使用实际 IP/DNS。 生产 `/runtime-config` 是只读资源,`BACKEND_PUBLIC_URL` 默认 `same-origin`,API/WS 随浏览器当前协议、主机与端口解析,局域网访问无需另填本机 IP。仅分离后端等明确需要绝对地址时设置 HTTP(S) 覆盖。下面 `192.168.103.18` 是可选显式覆盖示例,使用时替换为实际地址;普通同源部署省略该变量,本机 `8080` 测试只需设置 `PROD_HTTP_PORT=8080`。 ```powershell # 仅为内网示例;实际部署时替换为目标机器/网络地址。 $env:BACKEND_PUBLIC_URL = "http://192.168.103.18" $env:PROD_HTTP_PORT = "80" # 供二次开发客户端直接访问 API/docs 的 backend 端口。 $env:BACKEND_HTTP_PORT = "8144" docker compose -f docker-compose.prod.yml up -d --build ``` `8080` 只是示例,用户可以自定义端口。`PROD_HTTP_PORT` 控制 Nginx 的宿主机端口;默认 `same-origin` 自动随浏览器端口解析,仅显式 HTTP(S) 覆盖才需核对 `BACKEND_PUBLIC_URL` 的目标端口;`BACKEND_HTTP_PORT` 控制二次开发客户端直连 backend API/docs 的宿主机端口。Compose 的顺序是 `宿主机端口:容器端口`,因此生产文件等价于: ```yaml ports: - "${BACKEND_HTTP_PORT:-8144}:8144" # 宿主机 -> backend 容器 - "${PROD_HTTP_PORT:-80}:80" # 宿主机 -> Nginx 容器 ``` 例如可以设置 `PROD_HTTP_PORT=9080`、`BACKEND_PUBLIC_URL=http://127.0.0.1:9080`、`BACKEND_HTTP_PORT=18144`。如果直接编辑 YAML,`- "18144:8144"` 只会把 backend 的宿主机端口改成 `18144`;只要容器仍监听 `8144`,右侧不要改。确实要改容器内部端口时,还要同步修改 `backend/Dockerfile.prod`、backend 的 healthcheck/expose,以及 Nginx 的 `proxy_pass` 目标。修改端口变量或映射后要重新 recreate Compose 服务。 只修改 `frontend-js/dist` 时,重新构建前端并重启 Nginx 即可,不需要重新构建 backend 镜像: ```bash pnpm --dir frontend-js run build docker compose -f docker-compose.prod.yml restart nginx ``` 停止生产服务: ```bash docker compose -f docker-compose.prod.yml down ``` ### MSSQL 容器 + 宿主机源码运行 这个入口只启动 MSSQL。首次使用先从模板创建 `backend/.env`,分别设置 `MSSQL_SA_PASSWORD`(容器初始化)和 `MSSQL_PASSWORD`(backend 连接);默认 `MSSQL_USER=sa` 时两者应保持一致。宿主机 backend 使用同一文件连接 `localhost:14333`: 默认后端地址: ```text http://127.0.0.1:8144 ``` ```powershell cp backend/.env.example backend/.env docker compose -f docker-compose.mssql.yml up -d --build Push-Location backend uv sync --locked uv run alembic upgrade head uv run python scripts/seed_devices.py Pop-Location ``` 上面的 migration 和设备 seed 只在需要初始化/升级数据库时显式执行,不会由 Docker build 或 Compose backend 启动自动执行。如果需要为四个 ECharts 面板写入可重复的 24 小时开发样例数据,`--date` 必须使用 `YYYY-MM-DD`(例如 `2026-08-18`),当天日期和固定回放日期二选一: Linux/macOS: ```bash cd backend # 当前主机日期,例如输出 2026-08-18 seed_date=$(date +%F) # 固定回放日期时改用这一行,不要同时执行两次赋值 # seed_date='2026-08-18' uv run python scripts/seed_dashboard_metrics.py --date "$seed_date" --dry-run uv run python scripts/seed_dashboard_metrics.py --date "$seed_date" --source-key seed-dashboard cd .. ``` Windows PowerShell: ```powershell # 使用 DASHBOARD_SITE_TIMEZONE(通常为 Asia/Shanghai)的当天日期 $seedDate = Get-Date -Format 'yyyy-MM-dd' # 固定回放日期时改用这一行,不要把日期写进 -Format # $seedDate = '2026-08-18' Push-Location backend uv run python scripts/seed_dashboard_metrics.py --date $seedDate --dry-run uv run python scripts/seed_dashboard_metrics.py --date $seedDate --source-key seed-dashboard Pop-Location ``` `--date` 是必填的自然日。上面 `2026-08-15` 只是示例;如果不是现场时区的当天,默认 Dashboard 查询当天时不会显示这批历史样例,回放时必须让 Dashboard/API 也查询相同日期。 启动宿主机 backend: ```powershell Push-Location backend uv run python run.py ``` 在另一个终端启动统一前端: ```bash pnpm --dir frontend-js run dev -- --host 0.0.0.0 --port 5178 ``` 停止 MSSQL 容器: ```bash docker compose -f docker-compose.mssql.yml down ``` `MSSQL_SA_PASSWORD` 供 MSSQL 容器初始化内置 `sa`,`MSSQL_PASSWORD` 供 backend 连接数据库;当前 backend 使用 `MSSQL_USER=sa` 时,两者实际值必须一致。修改 env 不会重置当前场景 volume(MSSQL-only 为 `data-twin-database-only-volume`,全容器 dev 为 `data-twin-dev-volume`)中已经保存的密码;如果已有 volume,应继续填写创建该 volume 时使用的密码。 后端说明、API 契约和验收记录见: - [backend/README.zh-CN.md](backend/README.zh-CN.md) - [backend/API_CONTRACT.zh-CN.md](backend/API_CONTRACT.zh-CN.md) ## 统一前端 GLB 模型放到前端共享资产目录: ```text frontend-js/public/runtime-assets/models/ ``` 启动 Dashboard 与 Site Adaptation: ```bash cd frontend-js pnpm install pnpm run dev -- --host 0.0.0.0 --port 5178 ``` 打开: ```text http://127.0.0.1:5178/ http://127.0.0.1:5178/site-adaptation/runtime-connection ``` 前端说明见:[frontend-js/README.zh-CN.md](frontend-js/README.zh-CN.md) ## AIIS 治理机制 本项目以阶段式 3MD 作为任务事实,并在每个写入型任务中记录 Execution Mode。修改文件前阅读 [AGENTS.md](AGENTS.md),当前任务索引见 [PLAN.zh-CN.md](PLAN.zh-CN.md)。Session registry 与 Agent Team runtime activation 不属于本 project-governance 合同。 ## 后端数据库现场配置(DTB-042) `DATABASE_CONFIG_ENABLED` 默认 `true`:启用下述 SQLite 配置管理规则。设置为 `false` 时,backend 只使用结构化 MSSQL env,不创建、读取或修改 SQLite;已有文件保留,重新启用并重启后原记录仍优先。源码 `.env` 与 prod `.env.prod.docker` 设置 `true`,dev `.env.dev.docker` 设置 `false`,避免 dev 目录挂载共用宿主机 SQLite 时发生地址冲突。开关与自动化测试用 `DATABASE_CONFIG_TEST_MODE` 无关。修改 Compose env 需要 recreate backend,普通 restart 不更新注入值;源码运行需重启进程。 关闭时,四个配置管理 API 对合法请求统一返回 HTTP 403 / `CONFIG_DISABLED`,判断先于管理员认证,不返回 env 或 SQLite 配置,也不执行候选连接测试。TSS 清除旧配置和密码,显示禁用提示并停用编辑/测试/保存/状态刷新,保留重新读取;读取成功才解除禁用。首次读取仍沿用凭据弹窗;切换服务器回到未读取状态。 以下 SQLite 来源优先级和管理操作说明仅适用于开关启用时。 TSS「连接与诊断」第一项「数据库配置」通过 HTTP 管理 backend 的 MSSQL 连接。原「数据库连接测试」仍只控制 TSS 本机直连。 backend 首次使用 env;存在 `runtime-config/database.sqlite3` 的完整记录时优先使用 SQLite。保存后需重启 backend 才生效;连接失败不自动回退 env。业务数据库不可用时,管理 API 和进程存活入口仍可使用。 dev 使用已有 `./backend:/app`;prod 使用 `data-twin-prod-runtime-config-volume` 命名卷,不挂 backend 源码。SQLite 包含明文数据库密码,禁止提交或打入镜像。管理账号密码放对应 backend 运行 env 的 `CONFIG_USER` / `CONFIG_PASSWORD`,缺失时拒绝操作;此 HTTP 管理入口仅用于已接受未加密传输的内网。 源码使用及接口详见 [backend README](backend/README.zh-CN.md);备份与恢复见 [配置目录说明](backend/runtime-config/README.zh-CN.md)。现有 prod 首次改为新代码仍需构建/交付镜像;本文不表示已部署或已验证真实 MSSQL。 ## prod 同源访问(DTB-043) prod 默认下发 `connection.backendBaseUrl: "same-origin"`。浏览器按当前页面协议、主机和端口生成 API/WS 地址,经 Nginx `/api/`、`/ws/` 转发到 backend:8144;部署IP改变无需改前端构建。显式 `BACKEND_PUBLIC_URL` HTTP(S) 地址仍优先,供分离部署使用。源码与 dev Compose 默认也使用 same-origin,由 Vite 转发 API/WS。初始化页 source=production 时只读,保存/恢复默认禁用;dev/preview保持可写。 在部署服务器更新源码后,先运行 `pnpm --dir frontend-js run build`。要使用默认同源,在 PowerShell 执行 `Remove-Item Env:BACKEND_PUBLIC_URL -ErrorAction SilentlyContinue`,并检查Compose根.env/--env-file/系统环境没有遗留覆盖;不要清除有意保留的分离部署地址。然后执行 `docker compose -f docker-compose.prod.yml up -d --no-deps --force-recreate nginx`。确认 `/runtime-config` 返回same-origin,再刷新页面。前端和模板必须配套升级;旧前端不支持新标记,回滚时一起恢复旧前端与绝对地址配置。数据库B地址由backend管理,与本配置无关。 ### 开发环境同源访问(DTB-043 r2) 源码运行及 dev Compose 默认使用 `same-origin`,局域网设备打开 `http://运行前端的电脑IP:5178/dashboard` 即可。Vite 使用服务器端变量 `SCENE_RUNTIME_ASSET_PROXY_TARGET` 转发 `/api/`、`/ws/` 和 `/runtime-assets/scenes/`;源码默认目标 `http://127.0.0.1:8144`,dev Compose 注入 `http://backend:8144`,端口发布为 `5178:5178`。该目标不会进入浏览器配置。 升级后重启源码 Vite;dev Compose 执行 `docker compose -f docker-compose.dev.yml up -d --no-deps --force-recreate frontend-js`。已有 `frontend-js/config/runtime-config.user.json` 优先于默认文件:如仍保存旧回环地址,在初始化配置页将 Backend 基础地址改为 `same-origin`,保存并重新加载;保留有意设置的显式 HTTP(S) 地址。本机已有用户文件已调整,其他电脑的 gitignored 用户配置不会随 Git 更新。数据库 env/SQLite 配置不变。 前端镜像以仓库根为 context、使用 `frontend-js/Dockerfile`。前端目录外仅引入 `tools/model-assets/shared` 纯候选核心:dev 只读挂载,prod 复制进模型管理器镜像。`frontend-js/Dockerfile.dockerignore` 排除前端环境文件和缓存。端口及后端职责不变。 设备部件管理合同(DTB-046):资料/卡片按 deviceId+partId,旧入口多行提示需选部件;Dashboard 传递可用 clickPartId,TSS 摘要携带 partId。数据库标签持久编辑,YAML 仅补缺。场景登记独立于初始状态,正式切换须先进行旧资料归属预览。详见 [后端合同](backend/README.zh-CN.md)。 历史DTB-050设备部件整链(新版独立点击以本文DTB-062段为准):上传并确认 GLB 清单后,在 TSS 预览差异并只登记缺失资料/场景成员;初始状态必须明确选择。卡片以 `deviceId + partId` 独立保存。Site Adaptation 的 Mapping 默认使用同身份详情目标,也可明确把多个源模型绑定到同一个已登记部件;发布激活后需显式重载,已加载 Runtime 保留原版本。展示目标不会改变源部件动作或显隐身份。旧 GLB/Mapping 兼容 catalog 和 `tools/model-assets` 离线复核生成器继续保留。整链验证、未完成的原生/现场 gate 和最终验收只记录在 [DTB-050](plans/DTB-050-device-part-workflow-integration/spec.md) 任务 bundle,不由构建成功推定。 ## DTB-057:统一名称与部件卡片 `device_labels` 是设备/部件名称的唯一来源:`part_id IS NULL` 表示设备,非空表示精确部件;同身份/locale 唯一。最终 schema 0040 删除 `devices.device_name/part_name`,业务资料、状态与 `extra_data.statusCard` 不变。API 仍返回解析后的 deviceName/partName:请求语言 → zh-CN → en-US → 原始 ID;不借其他部件名称。显式 locale 优先 Accept-Language,默认 zh-CN。YAML 仅补缺,支持同设备条目下 `parts:[{partId,labels:{...}}]`。 设备 `/api/devices/{deviceId}/labels` 与部件 `/api/devices/{deviceId}/parts/{partId}/labels` 的 GET 返回 `{deviceId,partId,items,labelsVersion}`,含原始全部语言记录。PATCH 为 `{labels:{"zh-CN":"名称","en-US":"Name"},expectedLabelsVersion:"GET所得版本"}`,只更新提交语言,省略保留,空名/未知语言拒绝;成功后回读。缺版本422,竞争冲突HTTP409/LABEL_VERSION_CONFLICT;标签版本包含全部历史语言,名称更新不改devices.updated_at。资料POST/PATCH提交deviceName/partName及snake_case旧字段均422且不部分写入;卡片存储合同不变。 TSS分别编辑设备/部件中英文标签,普通资料不再编辑单值partName。查看器显示原始语言标签与解析名;切换语言刷新显示,保留未保存输入与原并发版本。Dashboard每次点击默认“全部部件”,仅列当前场景目标设备登记部件,按原始partId稳定排序;每组显示原始state.status/positionKey,缺值为—。具体部件页只显示原statusCard条目与布尔点,无条目为空态。Mapping目标身份和冻结版本不变,名称刷新不重载草稿。Backend/locale变化隔离缓存和迟到请求。 `/ws/devices` 连接query locale优先握手Accept-Language,连接内语言固定,切语言重连并丢弃旧消息;场景模型WS协议不变。外部旧标签客户端必须补版本,旧资料客户端必须移除名称输入。 迁移固定分工:旧部件工具到0036,名称回填工具止于0039;[独立0040清理工具](docs/DEVICE_NAME_CLEANUP_MIGRATION.zh-CN.md)导出完整存档、原样复制确认后Apply,只删除两旧名称列,不重插devices、不改labels。新工具不要求手填声明,保留自动目标/hash/事务快照校验;旧名称verify --finalize退役。真实迁移/停启/部署另授权,执行前暂停相关写入并使用配套新程序;新ORM不能早于0039,旧ORM不能用于0040。自动downgrade阻断,恢复须保全每行原名及升级后标签。 ## DTB-062:独立模型点击配置 DTB-065:旧 Mapping `interactions` 仅保留历史载荷、冻结校验和引用保护,不控制点击;动作 Mapping 导出格式不变。独立点击 JSON 备份导入/导出保留,仍须预览、保存回读和显式重载。 `/site-adaptation/model-click-ownership` 按场景管理设备聚合卡片目标,不选动画 Mapping 版本。默认自动识别严格解析 `{deviceId}__{partId}--{stateKey}` 并核对场景登记/资料;人工覆盖仅指定源模型及目标 deviceId,优先于自动识别。关闭自动识别仍执行覆盖。多源可指向同设备,源动画、状态、高亮/聚焦不转移给目标。 独立表 `scene_model_click_configurations` 每场景一条,保存 auto_recognize、overrides_json、config_version 和数据库时间。覆盖绑定 sourceModelSha256;旧SHA规则保留且不适用,不自动重绑。预览后保存并回读,configVersion/清单/登记变化使旧预览失效。只在显式加载/重载场景时 pin;保存不热生效,Mapping发布/回滚不改变点击配置。 DTB-065:无独立记录统一使用 default、configVersion=0、autoRecognize=true,按当前清单及登记解析,不自动INSERT,也无需先保存。点击读取、预览和保存不查询动画 Mapping;没有旧规则导入或确认流程。读取失败或SHA不符不能当无记录,GLB/动画仍加载,仅点击禁用并报告错误。正常命名无需逐个绑定;操作见[独立点击指南](docs/SCENE_MAPPING_EDITOR_SOP.zh-CN.md#card-binding)。Mapping 页面仅保留素材绑定及独立点击页导航。 迁移0043仅新增独立表,不改旧Mapping JSON;真实升级需另行授权。降级只允许结构符合预期且为空、无外部依赖的表,有配置时阻断。旧程序忽略新表会恢复旧点击行为,auto=false可能失效,程序回退前须保全核对;回滚Mapping不是回滚点击设置。 DTB-059 r3 当前26表范围包含独立点击配置。导出 scene_model_click_configurations 的记录需选择 data;structure 恢复后为空。配套 GLB 仍单独交付,旧25表包不是兼容的 r3 恢复包。