@microi.net/cli 4.6.4 → 4.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/mcp-server.js +98 -92
  2. package/dist/microi-cli.js +177 -26
  3. package/dist/microi-skills.meta.json +147 -141
  4. package/dist/microi.skills/.microi-skills-version.json +2 -2
  5. package/dist/microi.skills/README.md +3 -2
  6. package/dist/microi.skills/ai-engine/SKILL.md +38 -11
  7. package/dist/microi.skills/app-store/SKILL.md +134 -104
  8. package/dist/microi.skills/microi-ai-application/SKILL.md +8 -0
  9. package/dist/microi.skills/microi-client-frontend/SKILL.md +403 -403
  10. package/dist/microi.skills/microi-db-schema/SKILL.md +165 -165
  11. package/dist/microi.skills/microi-deployment/SKILL.md +29 -3
  12. package/dist/microi.skills/microi-docs-coverage/references/capability-map.md +4 -3
  13. package/dist/microi.skills/microi-docs-coverage/scripts/audit-doc-skill-coverage.mjs +10 -3
  14. package/dist/microi.skills/microi-form-engine/SKILL.md +165 -165
  15. package/dist/microi.skills/microi-system-delivery/SKILL.md +207 -200
  16. package/dist/microi.skills/microi-ui/SKILL.md +330 -330
  17. package/dist/microi.skills/microi.v8.js +1818 -1758
  18. package/dist/microi.skills/ocr-engine/SKILL.md +111 -0
  19. package/dist/microi.skills/ocr-engine/agents/openai.yaml +4 -0
  20. package/dist/microi.skills/page-engine/SKILL.md +2 -0
  21. package/dist/microi.skills/performance-testing/SKILL.md +2 -2
  22. package/dist/microi.skills/playwright-e2e/SKILL.md +14 -40
  23. package/dist/microi.skills/print-engine/SKILL.md +9 -3
  24. package/dist/microi.skills/report-engine/SKILL.md +1 -1
  25. package/dist/microi.skills/translate-engine/SKILL.md +47 -5
  26. package/dist/microi.skills/ui-design/SKILL.md +1596 -1596
  27. package/dist/microi.skills/ui-design/assets/templates/MCI-DESIGN.md +199 -199
  28. package/dist/microi.skills/ui-design/references/design-pattern-library.md +184 -184
  29. package/dist/microi.skills/ui-design/references/mci-design-contract.md +163 -163
  30. package/dist/microi.skills/v8-file-upload/SKILL.md +8 -0
  31. package/dist/microi.skills/v8-frontend-events/SKILL.md +4 -1
  32. package/dist/microi.skills/v8-frontend-events/references/bluetooth-print.md +28 -22
  33. package/dist/microi.skills/v8-http-integration/SKILL.md +22 -1
  34. package/dist/microi.skills/v8-saas-multi-tenant/SKILL.md +2 -1
  35. package/dist/microi.skills/v8-security/SKILL.md +7 -6
  36. package/dist/microi.skills/v8-utilities/references/server-api-index.md +1 -0
  37. package/dist/microi.skills/workspace-conventions/SKILL.md +15 -23
  38. package/package.json +1 -1
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: ocr-engine
3
+ description: 为 Microi 吾码集成、配置、调用和验收通用 OCR 能力。处理 V8.OCR、/api/ocr、PaddleX/PaddleOCR 服务、SaaS 租户 OCR 配置、图片或 PDF 文字识别、OCR 安全边界、Docker 部署和多节点交付时使用。
4
+ ---
5
+
6
+ # Microi OCR 引擎
7
+
8
+ ## 先读取相关规范
9
+
10
+ - 涉及租户配置时,读取 `../v8-saas-multi-tenant/SKILL.md`。
11
+ - 涉及外部 OCR 服务时,读取 `../v8-http-integration/SKILL.md`。
12
+ - 涉及 Base64、上传文件或私有文件时,读取 `../v8-file-upload/SKILL.md`。
13
+ - 涉及权限、密钥、日志或匿名接口时,读取 `../v8-security/SKILL.md`。
14
+ - 涉及数据库字段和表单 Tab 时,读取 `../microi-db-schema/SKILL.md`。
15
+
16
+ ## 固定架构
17
+
18
+ Microi 后端只实现统一 OCR 网关、租户隔离、协议适配和安全治理,不在 .NET 进程内训练或维护 OCR 模型。默认提供方为独立部署的 PaddleX OCR 服务;业务代码只能调用 `IMicroiOcr`、`V8.OCR` 或 `/api/ocr/recognize`,不得直接读取 SaaS 密钥并自行拼接 HTTP 请求。
19
+
20
+ 同步识别必须绑定当前请求和当前租户。批量、超大文件或长耗时 OCR 应进入共享数据库/MQ/outbox,以全局任务 Id 做幂等;不得把任务状态、队列或锁只放在单机内存中。
21
+
22
+ ## SaaS 配置
23
+
24
+ 配置位于 `sys_osclients` 的独立“OCR识别”Tab:
25
+
26
+ | 字段 | 用途 | 默认值 |
27
+ |---|---|---|
28
+ | `OcrEnabled` | 租户总开关,默认关闭 | `0` |
29
+ | `OcrProvider` | `PaddleX` 或 `PaddleXHighStability` | `PaddleX` |
30
+ | `OcrEndpoint` | OCR 服务完整接口地址 | 空 |
31
+ | `OcrApiKey` | 可选 Bearer 密钥,只允许后端使用 | 空 |
32
+ | `OcrHeadersJson` | 可选服务端固定请求头 JSON | 空 |
33
+ | `OcrTimeoutSeconds` | 单次超时秒数 | `60` |
34
+ | `OcrMaxFileMB` | 单文件大小上限 | `20` |
35
+ | `OcrMaxPages` | PDF 页数上限 | `10` |
36
+ | `OcrMinConfidence` | 返回文本最低置信度 | `0` |
37
+
38
+ 这些配置不得投影到 `V8.OsClientModel`,不得由前端请求覆盖,不得写入普通日志。没有启用、没有 endpoint 或配置无效时必须失败关闭。
39
+
40
+ ## 调用
41
+
42
+ 接口引擎或后端表单事件中:
43
+
44
+ ```js
45
+ var result = await V8.OCR.Recognize({
46
+ FileByteBase64: V8.FilesByteBase64.invoice,
47
+ FileName: 'invoice.png',
48
+ UseDocOrientationClassify: true,
49
+ UseDocUnwarping: true,
50
+ UseTextlineOrientation: true,
51
+ TextRecScoreThresh: 0.5,
52
+ ReturnWordBox: false
53
+ });
54
+
55
+ if (result.Code !== 1) {
56
+ return result;
57
+ }
58
+
59
+ return {
60
+ Code: 1,
61
+ Data: {
62
+ Text: result.Data.Text,
63
+ Pages: result.Data.Pages,
64
+ Provider: result.Data.Provider
65
+ }
66
+ };
67
+ ```
68
+
69
+ ASP.NET 客户端调用 `POST /api/ocr/recognize`,请求体与 `V8.OCR.Recognize` 一致,并携带正常登录 Token。`OsClient` 以 Token 解析结果为准。
70
+
71
+ 标准成功结果包含 `Provider`、`Text`、`Pages`、`ElapsedMilliseconds`。每页包含 `PageIndex`、`Text`、`Regions`,每个区域包含 `Text`、`Confidence` 和归一化后的 `Polygon`。
72
+
73
+ ## 协议与输入边界
74
+
75
+ - `PaddleX` 使用基础服务协议 `POST /ocr`。
76
+ - `PaddleXHighStability` 使用 KServe 协议 `POST /v2/models/ocr/infer`。
77
+ - 接受 PDF、PNG、JPEG、BMP、GIF、TIFF、WebP;同时检查文件扩展名、Base64 和文件魔数。
78
+ - 固定 `visualize=false`,避免服务返回大体积可视化图片。
79
+ - 由服务端限制文件大小、超时、PDF 页数、响应体大小和最低置信度。
80
+ - 禁止接受调用方传入 endpoint、API key、任意请求头、代理地址或本地文件路径,防止 SSRF 和密钥绕过。
81
+ - 日志只记录租户、提供方、状态码、耗时和安全裁剪后的错误,不记录文件 Base64、识别原文、API key 或完整响应。
82
+
83
+ ## Docker 与多节点
84
+
85
+ - OCR 模型服务独立部署,固定 PaddleX/PaddlePaddle/模型版本;不要使用浮动 `latest` 直接上线。
86
+ - CPU 基线位于 `../../Microi.Server/Microi.OCR/deploy/paddlex/`,固定 PaddleX 3.6.1 与 PaddlePaddle 3.2.2;公开镜像固定为 `registry.cn-hangzhou.aliyuncs.com/microios/paddlex-ocr:3.6.1-paddle3.2.2-cpu`,当前只交付 `linux/amd64`。PaddlePaddle 3.3.0 存在 CPU oneDNN PIR 推理兼容问题,在完成真实图片回归前不得升级。
87
+ - 发布镜像使用同目录 `publish-image.ps1`:它从根目录发布配置读取凭据,通过隔离 Docker 配置和 `--password-stdin` 登录,推送后退出并匿名回读公开摘要。不得在命令行、日志或文档中展开用户名/密码,也不得只凭 `docker push` 返回成功就宣布国内镜像可用。
88
+ - 发布镜像时执行 `create_pipeline("OCR")` 预置默认产线模型。运行时使用 named volume 挂载 `/home/microi/.paddlex`,让 Docker 首次创建卷时从镜像复制模型;不要改成空宿主机 bind mount,否则会遮住镜像内的预置模型并触发重新下载。
89
+ - OCR 宿主机端口只绑定 `127.0.0.1`;Docker 化 API 与 OCR 同时加入 external bridge 网络 `microi-ocr`,一键安装的内部 endpoint 固定为 `http://microi-install-ocr:8080/ocr`。不得通过公网/LAN 回环调用同机 OCR。
90
+ - `install-microi.sh` 默认安装 OCR。必须依次满足“固定镜像拉取并回读为 amd64 → OCR healthy → API liveness → Upgrade29 的 9 个物理字段数据库回读 → 唯一活动主租户 → 配置写入后回读 → API 重启 readiness”才设置 `OcrEnabled=1`;任一步失败都保持失败关闭。API liveness 后立即回读字段,每秒一次且最多 15 秒;正常升级应首轮命中,镜像过旧或迁移失败应快速报错,禁止无意义等待 5 分钟。不要用安装脚本直接伪造 `diy_field` 元数据绕过 Upgrade29。
91
+ - API/Web 官方浮动 `latest` 必须在 Compose 启动时强制回源拉取,避免旧本机镜像通过 liveness 却缺少 Upgrade29。字段门禁失败后可以输出已生成端口、密码、目录和容器状态供恢复,但必须明确标记“安装未完成”、保留非零退出码,并显示 OCR SaaS 配置未完成;恢复汇总不是启用 OCR 的依据。
92
+ - OCR 使用固定不可变版本,不加入只跟踪 API/Web 浮动标签的 Watchtower 自动更新列表;升级镜像时先发布新 tag、匿名回读 digest/架构,再修改 Compose 与安装器。
93
+ - 登录国内镜像源必须从本机发布配置读取凭据并走 `docker login --password-stdin`,不得输出密码。推送成功不是发布验收,必须使用隔离的匿名 Docker config 回读 manifest/digest,必要时再做匿名拉取。
94
+ - 不要在内存不足的共享开发机上直接构建模型镜像。构建前检查物理内存、Docker 占用与同类进程;保留至少 `max(6 GB, 物理内存 20%)`,不足时延后构建而不是停止他人服务。
95
+ - API 多节点共享同一个或同一组 OCR endpoint;每节点仅保留无状态 `HttpClient`。
96
+ - OCR 服务至少配置 readiness、并发上限、CPU/GPU 资源上限、请求体上限和访问控制。
97
+ - GPU 推理采用独立 Worker/服务池,避免 OCR 模型抢占 Microi API 内存。
98
+ - 滚动升级时保持旧新 OCR 响应协议兼容;协议变更先扩展解析器,再升级服务。
99
+
100
+ ## 验收门禁
101
+
102
+ 交付时分别报告:
103
+
104
+ 1. 源码:网关、V8、REST、SaaS 字段、密钥投影隔离是否齐全。
105
+ 2. 定向测试:基础协议、高稳定协议、低置信度过滤、错误响应、配置隔离。
106
+ 3. 数据库:目标 `OsClient` 的 Tab、字段和物理列经 MCP 写后回读。
107
+ 4. 服务:真实 PNG/JPEG/PDF 至少各一例,包含中英文、旋转和多页场景。
108
+ 5. 多节点:两个 API 节点同时调用,同租户限制一致,服务故障时均能超时/降级且不泄漏密钥。
109
+ 6. UI:SaaS 配置表单能查看独立 Tab、保存配置,密码字段不出现在普通前端上下文。
110
+
111
+ 没有真实 OCR endpoint、服务版本和样例识别结果时,只能声明“平台接入完成、运行验收待配置”,不能声明生产 OCR 已可用。
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Microi OCR 引擎"
3
+ short_description: "集成、配置和验证 Microi 通用 OCR 能力"
4
+ default_prompt: "Use $ocr-engine to integrate and validate tenant-isolated OCR in Microi."
@@ -257,6 +257,8 @@ $ApiBase$/apiengine/{ApiEngineKey}
257
257
 
258
258
  界面引擎嵌套必须使用 `pageengine-widget.vue` 直接加载 `form-renderer` 组件,不得使用 iframe。每个嵌套页面由 `PAGE_ENGINE_STORE_KEY` 注入独立的 Pinia store,避免子页面覆盖父页面 `formData`;递归页面 Id 通过 `PAGE_ENGINE_RENDER_CONTEXT_KEY` 检测并阻止循环嵌套。父容器和组件高度设为 `0` 表示自动高度,由最外层页面统一滚动。
259
259
 
260
+ `mic_page` 是按角色管理的运行资源:普通登录用户读取或嵌套页面时必须拥有菜单权限或高级表 `Read`,新增、修改、删除分别要求明确的 `Add`、`Edit`、`Del`;所有匿名 FormEngine 调用仍拒绝。角色页只展示服务端返回的分级策略,最终授权和当前操作者的平台管理员身份由后端主库复核。
261
+
260
262
  界面引擎渲染页会为 `_IsAdmin` 或 `Level >= 9999` 的用户提供“界面设计”入口,跳转 `/mic/autopage?Id={mic_page.Id}`。入口优先放入后台 TagsView 页签右键菜单,并在页面第一个容器标题栏右侧提供紧凑快捷入口,与 `moreOption` 等操作使用同一个 flex 操作区垂直居中、右对齐;不得额外占用页面高度、增加顶部空白或覆盖标题,非管理员不显示。嵌套 `pageengine` 也必须显示其自身页面的设计入口,并由父页面直接打开对应子页面设计器。
261
263
 
262
264
  首页编排可以组合 `aiengine`、`workcenter`、`diycalendar`、`diytable` 和一个占大区域的 `pageengine`。公告应优先通过绑定 `diy_notice` 的 `diytable` 渲染,使增删改权限继续由 `sys_menu + _RoleLimits` 控制;统计子页面由客户独立替换时,只需修改被嵌入的 `mic_page`,无需重做首页布局。
@@ -162,7 +162,7 @@ POST /api/formengine/DelFormData
162
162
 
163
163
  强制要求:
164
164
 
165
- - V8/Jint 默认超时、最大语句数、内存、递归深度必须保守,并提供环境变量或配置项给私有部署按机器规格放宽。
165
+ - V8/Jint 默认超时、最大语句数、内存、递归深度必须保守;需要按租户或机器规格调整时统一在 SaaS 引擎 `sys_osclients` 的受控字段或接口引擎自身配置中维护,并由代码硬上限夹住。禁止为此新增 API 环境变量或 `appsettings` 节点。
166
166
  - V8Engine.Run 入口必须有全局、租户级、接口/事件级并发阀门;过载时返回 `Code=0` 和“系统繁忙,请稍后重试”,不要继续进入事务和数据库。
167
167
  - HTTP 入口应在进入 Controller 前做全局、租户、路由、接口引擎级背压;过载时直接返回 DosResult 风格 JSON,保证前端能弹出明确提示。
168
168
  - 接口引擎配置里的 Timeout、MaxStatements、LimitMemory、LimitRecursion 不能无限放大,必须被平台级最大值夹住。
@@ -185,7 +185,7 @@ POST /api/formengine/DelFormData
185
185
 
186
186
  强制要求:
187
187
  - 长任务保护的核心是“并发阀门 + 排队限流 + 可配置超时”,不是粗暴拒绝。
188
- - 接口引擎/V8 默认执行窗口应能覆盖常见长任务,默认建议不少于 10 分钟;私有部署可通过环境变量继续放宽。
188
+ - 接口引擎/V8 默认执行窗口应能覆盖常见长任务,默认建议不少于 10 分钟;私有部署需要放宽时使用 SaaS 引擎 `sys_osclients` 的动态运行配置或接口引擎自身配置,并受平台代码硬上限约束,不得新增 API 环境变量或 `appsettings` 节点。
189
189
  - 入口限流对接口引擎/V8 应使用长排队窗口;只有排队窗口耗尽、请求被客户端取消、或平台资源已进入保护熔断时,才返回“系统繁忙/正在排队,请稍后重试”。
190
190
  - 不允许为了保护数据库而误杀合法批处理。真正需要治理的是无界并发、循环套循环查库、未分页大查询、外部接口无限等待和连接泄漏。
191
191
  - 对确实超过 HTTP/网关可承受时间的任务,应改造为后台任务/MQ/进度日志模式;后台任务进度优先通过吾码标准 WebSocket/SignalR 推送,不要让前端频繁轮询接口。但这属于交互形态升级,不应影响同步接口引擎的兼容性。
@@ -90,13 +90,12 @@ PW_HOME_PATH=/#/pages/index/index
90
90
 
91
91
  ## 本地测试账号自动发现
92
92
 
93
- 当没有显式传入 `PW_TEST_ACCOUNT` / `PW_TEST_PASSWORD` / `MICROI_OSCLIENT` 时,AI 不要先说“未登录无法测试”。必须先尝试读取本地后端配置:
93
+ 当没有显式传入 `PW_TEST_ACCOUNT` / `PW_TEST_PASSWORD` / `MICROI_OSCLIENT` 时,AI 不要把账号密码写入后端配置来制造旁路:
94
94
 
95
95
  1. 读取 `Microi.Server/Microi.net.Api/.microi-local`,取得当前环境名。
96
- 2. 读取 `Microi.Server/Microi.net.Api/appsettings.{环境名}.json`;若脚本显式传了 `PW_APPSETTINGS_PATH`,以该文件为准。
97
- 3. 优先在 `DevLoginBypass.Accounts` 中按 `OsClient` 匹配当前租户,读取 `Account` / `Password`;没有匹配时再用 `DevLoginBypass.DefaultAccount` / `DefaultPassword`。
98
- 4. 这些值只作为本地自动化登录输入或接口请求参数使用。日志、最终回复、截图说明、报告和异常消息中必须写成 `<redacted>` 或“本地配置凭据”,不要展开真实账号密码、Token、连接串或 Redis 密码。
99
- 5. 如果配置不存在或登录失败,再报告具体阻塞点,例如“未找到 `DevLoginBypass`”“本地后端未启动”“登录接口返回 Code=0”,不要泛泛说无法测试。
96
+ 2. 账号密码只从用户本轮明确提供、`PW_TEST_ACCOUNT` / `PW_TEST_PASSWORD`、CI Secret 或既有受保护登录态取得;`appsettings.*.json` 不再保存测试账号密码。
97
+ 3. 这些值只作为自动化进程的登录输入或接口请求参数使用。日志、最终回复、截图说明、报告和异常消息中必须写成 `<redacted>` 或“本地配置凭据”,不要展开真实账号密码、Token、连接串或 Redis 密码。
98
+ 4. 如果凭据不存在或登录失败,再报告具体阻塞点,例如“未提供受保护测试凭据”“本地后端未启动”“登录接口返回 Code=0”,不要泛泛说无法测试。
100
99
 
101
100
  ## 后端改动后的 E2E 前置动作
102
101
 
@@ -150,33 +149,11 @@ export async function automationLogin(page, {
150
149
  }
151
150
  ```
152
151
 
153
- ### 方式 B:配置驱动旁路(本地 localhost 调试用)
154
-
155
- `appsettings.{Env}.json`(如 `appsettings.iTdos.json` / `appsettings.json`)中的 `DevLoginBypass` 块:
156
-
157
- ```jsonc
158
- "DevLoginBypass": {
159
- "//": "Local Development only / E2E login bypass. Keep disabled in production.",
160
- "Enabled": true,
161
- "SkipCaptcha": true, // 跳过图形验证码
162
- "OnlyLoopback": true, // 必须保留 true;仅 Development + 127.0.0.1 / ::1 生效
163
- "DefaultAccount": "<default-account>",
164
- "DefaultPassword": "<default-password>"
165
- }
166
- ```
152
+ ### 选型口诀
167
153
 
168
- - 触发条件:`Enabled=true`,且后端环境为 `Development`,且请求来自本机回环地址。生产、容器反代、非回环来源均不得生效。
169
- - 效果:`SkipCaptcha=true` 时跳过验证码;请求未带账号/密码时自动填 `DefaultAccount`/`DefaultPassword`,仍会校验真实密码。
170
- - 与方式 A 区别:仅允许 Development + loopback。适合在本机用真实账号跑 UI 登录或直登;不要把它当成远端能力。
171
- - 生产环境务必保持 `Enabled=false` 或删除该块。
172
-
173
- `Microi.Client/scripts/run-form-engine-freeze-trace.mjs` 会在跑诊断前自动把 `DevLoginBypass` 写入 `appsettings.{Env}.json`;可用 `PW_CONFIG_DEV_LOGIN=0` 关闭该自动改写。
174
-
175
- ### 选型口诀
176
-
177
- - 容器/CI、无图形界面、要最稳 → **方式 A(`_AutomationTestLogin=true` + 真实密码)**,直接 request 拿 Token。
178
- - 本机调试、想顺带验真实密码或走真实 UI 登录 → **方式 B(DevLoginBypass)**。
179
- - 两者都失败时再退回 UI 兜底:填账号密码、点登录(参见 `tests/form-engine-freeze-trace.spec.mjs` 的 `loginThroughUiIfNeeded`)。
154
+ - 容器、CI、本机接口自动化都使用 **`_AutomationTestLogin=true` + 真实密码**,直接 request 拿 Token。
155
+ - 需要验证真实 UI 登录时,用同一真实账号密码填写页面;目标租户仍由 `sys_config.AutoTestSkipCaptcha` 决定是否允许自动化跳过验证码。
156
+ - 失败时再退回 UI 兜底并保留原始错误;禁止新增 `DevLoginBypass`、Dev Key `_DEV_BYPASS_`。
180
157
  - Token 可能在响应体 `Data.Token`,也可能在响应头 `Authorization`,两处都要兜底取。
181
158
  - 不要把 Token 明文写进最终报告/附件。
182
159
 
@@ -186,12 +163,12 @@ export async function automationLogin(page, {
186
163
  >
187
164
  > 在浏览器内做 E2E(点页面、拖拽、截图)时最稳的登录顺序:
188
165
  > 1. 跳到 `#/login`;
189
- > 2. 填从本地 `DevLoginBypass` 配置或环境变量读取到的账号密码;
190
- > 3. 验证码框随便填一个数字(`DevLoginBypass.SkipCaptcha=true` 时后端对 loopback 忽略验证码);
166
+ > 2. 填从受保护测试进程变量或用户本轮提供的真实账号密码;
167
+ > 3. 目标租户开启 `AutoTestSkipCaptcha` 时传自动化标记跳过验证码,否则按真实页面流程填写验证码;
191
168
  > 4. 点「登 录」,落到首页;
192
169
  > 5. 再 `location.hash = '#/<目标路由>'` 进入目标页。
193
170
  >
194
- > 直连接口验收(不进页面)才用方式 A 拿 Token。历史 `_DEV_BYPASS_` 只能在本机 DevLoginBypass 下替换为配置密码后继续校验,不能作为免密码能力。
171
+ > 直连接口验收(不进页面)使用自动化标记拿 Token;历史 `_DEV_BYPASS_`、Dev Key 和 `DevLoginBypass` 均不得继续使用。
195
172
 
196
173
  ## 服务自启动纪律(必做)
197
174
 
@@ -249,7 +226,7 @@ Pop-Location
249
226
  该入口会执行 `scripts/run-form-engine-freeze-trace.mjs`,完整流程如下:
250
227
 
251
228
  1. 自动配置 `Microi.Server/Microi.net.Api/Properties/launchSettings.json` 中指定 profile 的 `ASPNETCORE_ENVIRONMENT` 和 `DOTNET_ENVIRONMENT`。
252
- 2. 自动配置 `Microi.Server/Microi.net.Api/appsettings.{Env}.json` `DevLoginBypass`,用于本地测试账号、跳过验证码、只允许 loopback。
229
+ 2. `PW_TEST_ACCOUNT` / `PW_TEST_PASSWORD` 读取真实测试凭据;脚本不得修改后端 `appsettings.*.json`。
253
230
  3. 本地后端未启动时,自动进入 `Microi.Server/Microi.net.Api` 后执行 `dotnet run --launch-profile Microi.net.Api`。
254
231
  4. 启动 Playwright,打开指定前端页面,开启 `MicroiFormTrace`,采集 `window.__MICROI_FORM_TRACE__`、console、pageerror、当前 URL 和 Playwright trace。
255
232
  5. 页面卡住或断言失败时,先看最后一批 `[MicroiFormTrace #n]`,定位是停在 `runtime:*`、`diy-select:*`、`inform-v8-*`、`field-v8-*` 还是业务 console。
@@ -274,11 +251,8 @@ npm run test:form-freeze:auto
274
251
 
275
252
  - `PW_START_BACKEND=0`:不自动启动后端,只跑测试。
276
253
  - `PW_CONFIG_BACKEND=0`:不修改 `launchSettings.json`。
277
- - `PW_CONFIG_DEV_LOGIN=0`:不修改 `DevLoginBypass`。
278
- - `PW_APPSETTINGS_PATH=Microi.Server/Microi.net.Api/appsettings.iTdos.json`:明确指定配置文件。
279
- - `PW_BACKEND_PROFILE=Microi.net.Api`:指定 launch profile。
280
- - `PW_DEV_LOGIN_BYPASS=1`、`PW_DEV_SKIP_CAPTCHA=1`、`PW_DEV_ONLY_LOOPBACK=1`:控制本地登录旁路。
281
- - `PW_DEV_LOGIN_ACCOUNT`、`PW_DEV_LOGIN_PASSWORD`:只配置后端旁路账号密码;`PW_TEST_ACCOUNT`、`PW_TEST_PASSWORD` 同时作为 Playwright 登录账号密码。
254
+ - `PW_BACKEND_PROFILE=Microi.net.Api`:指定 launch profile。
255
+ - `PW_TEST_ACCOUNT`、`PW_TEST_PASSWORD`:仅注入当前自动化进程,必须使用真实账号密码且不得写回文件。
282
256
  - `PW_HEADED=0`:无头运行。
283
257
 
284
258
  诊断代码要遵守这些规则:
@@ -34,9 +34,15 @@ description: 生成和审查 Microi 打印引擎 Print Engine 模板 JSON。用
34
34
  |------|------|
35
35
  | PageObj | 页面模板定义(面板 + 元素布局) |
36
36
  | PrintObj | 打印数据(运行时填充到模板中) |
37
- | DataApi | 关联的接口引擎 Id(动态数据) |
38
-
39
- ## PageObj 模板结构
37
+ | DataApi | 关联的接口引擎 Id(动态数据) |
38
+
39
+ ### `mic_print` 权限边界
40
+
41
+ - `mic_print` 是按角色管理的运行资源,不是只能由 `Level >= 9999` 读取的控制面表。打印渲染器通过 FormEngine 读取模板时,当前角色必须拥有菜单权限或高级表权限中的 `Read`;否则应明确返回 `NoAuth`,不能为兼容改成匿名读取。
42
+ - 模板新增、修改、删除分别要求明确的 `Add`、`Edit`、`Del`。只需要打印的业务角色通常只授予 `Read`,不要顺带授予设计权限。
43
+ - 角色授权界面只负责展示服务端策略。角色增删改接口必须从主库复核当前操作者确为活动平台管理员,不能相信 Postman 请求体中的 `_IsAdmin`、`Level`、`RoleIds` 或 `OsClient`。
44
+
45
+ ## PageObj 模板结构
40
46
 
41
47
  ```json
42
48
  {
@@ -23,7 +23,7 @@ description: Microi 报表引擎设计与验收规范。用于 Rpt_Report 虚拟
23
23
  - 报表数据源必须应用当前租户和服务端用户数据范围。菜单权限不会自动保护任意聚合 SQL。
24
24
  - 聚合结果也可能泄露敏感信息;小样本、人员薪资、客户金额等需最小分组阈值或字段脱敏。
25
25
  - SQL 动态值参数化,维度/排序/指标使用白名单映射,不接收原始 SQL、列名或 `GROUP BY`。
26
- - 平台保护表不能作为普通用户报表数据源。
26
+ - 管理员专用平台表不能作为普通用户报表数据源;只读委托表只有获得真实 `Read` 授权后才能查询,`mic_page/mic_print` 继续按角色权限处理。
27
27
 
28
28
  ## 写入型报表
29
29
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: translate-engine
3
- description: Microi 翻译引擎与多语言词条规范。用于 V8.TranslateEngine.Translate、GetLang、GetLangData、语言码、供应商配置、租户隔离、缓存、批量翻译和验收。
3
+ description: Microi 翻译引擎与多语言词条规范。用于 V8.TranslateEngine 文本/批量/HTML/检测/语言列表/文件/建议/健康能力、HTTP 与 MCP 翻译调用、GetLang 词条、供应商配置、租户隔离、缓存和验收。
4
4
  ---
5
5
 
6
6
  # Microi TranslateEngine
@@ -10,16 +10,39 @@ description: Microi 翻译引擎与多语言词条规范。用于 V8.TranslateEn
10
10
  ```js
11
11
  var r1 = V8.TranslateEngine.Translate('你好', 'en');
12
12
  var r2 = V8.TranslateEngine.Translate('hello', 'cn', 'en');
13
+ var full = V8.TranslateEngine.TranslateText({
14
+ SourceTexts: ['你好', '世界'], FromLang: 'auto', Lang: 'en',
15
+ Format: 'text', Alternatives: 2
16
+ });
17
+ var detected = V8.TranslateEngine.Detect({ SourceText: 'Bonjour' });
18
+ var languages = V8.TranslateEngine.GetLanguages();
19
+ var health = V8.TranslateEngine.Health();
20
+ var suggestion = V8.TranslateEngine.Suggest({
21
+ SourceText: 'Hello', SuggestedText: '你好', FromLang: 'en', Lang: 'zh'
22
+ });
13
23
  var text = V8.TranslateEngine.GetLang('NoAuth', 'cn');
14
24
  var item = V8.TranslateEngine.GetLangData('NoAuth');
15
25
  var code = V8.TranslateEngine.GetLangCode('NoAuth');
16
26
  ```
17
27
 
18
- `Translate` 返回 `DosResult`,不要把结果对象当字符串;先检查 `Code`,再读取 `Data`。`GetLang` 返回词条文本。
28
+ `Translate` 返回 `DosResult`,`Data` 为兼容的单条译文字符串。`TranslateText` 返回包含单条/批量译文、检测语言、候选译文和格式的完整结构。其余业务方法:
29
+
30
+ | 方法 | 契约 |
31
+ |---|---|
32
+ | `TranslateText` | `SourceText/SourceTexts` 二选一;`FromLang=auto`;`Format=text/html`;`Alternatives=0..10` |
33
+ | `Detect` | 返回 `{Language, Confidence}[]` |
34
+ | `GetLanguages` | 返回当前服务真实安装的 `{Code,Name,Targets}[]` |
35
+ | `TranslateFile` | TXT/HTML/ODT/ODP/DOCX/PPTX/XLSX/EPUB/PDF Base64 输入,Base64 文件输出 |
36
+ | `Suggest` | 写入启用了 suggestions 的 LibreTranslate 服务;不是多候选翻译 |
37
+ | `Health` | 只返回健康和业务能力摘要,不返回 URL/Key |
38
+ | `GetLang/GetLangData/GetLangCode` | 读取 `diy_lang`,不调用翻译供应商 |
39
+
40
+ LibreTranslate 的 `/frontend/settings`、API Key 管理、`/metrics` 和 Web UI 是运维控制面,不得从普通 V8/HTTP/MCP 代理。
19
41
 
20
42
  ## 租户与密钥
21
43
 
22
44
  - V8 调用统一绑定当前 `V8TenantContext`。普通租户传其它 `OsClient` 不会跨租户翻译或读取配置。
45
+ - 普通租户未配置供应商时失败关闭,不得隐式回退借用主租户翻译地址、密钥或额度。
23
46
  - Provider、Endpoint、Key、Secret、ApiKey 等只保存在服务端租户配置;不得进入前端 `SysConfig`、日志、错误响应或业务表。
24
47
  - 主租户显式跨租户只允许可信控制面 C# 调用,不由 HTTP 参数建立信任。
25
48
 
@@ -37,7 +60,7 @@ var code = V8.TranslateEngine.GetLangCode('NoAuth');
37
60
 
38
61
  ## LibreTranslate 自托管
39
62
 
40
- LibreTranslate 是可选动态翻译供应商,不是 `diy_lang` 的替代品。一键安装默认不部署;只有用户明确选择时才生成编排、随机 API Key 和语言模型清单。语言预设为:
63
+ LibreTranslate 是动态翻译供应商,不是 `diy_lang` 的替代品。一键安装默认部署;安装选择直接 Enter 等同 `1`,语言套餐直接 Enter 等同基础套餐 `1`。只有用户明确输入 `0` 才跳过编排。语言预设为:
41
64
 
42
65
  1. `zh,zt,en`;
43
66
  2. 预设 1 加 `ja,ko,vi,th,id,ms,tl`;
@@ -47,10 +70,26 @@ LibreTranslate 是可选动态翻译供应商,不是 `diy_lang` 的替代品
47
70
 
48
71
  服务端统一从 SaaS 引擎租户配置读取 `TranslateProvider`、`TranslateUrl`(兼容 `TranslateApiUrl` / `LibreTranslateUrl`)、`TranslateApiKey`(兼容 `TranslateKey`)和 `TranslateTimeout`;不要再为翻译供应商增加 API 容器环境变量。密钥不得进入前端、日志或文档示例的固定默认值。
49
72
 
50
- 一键安装在 API Key 数据库预初始化成功、正式容器进入运行状态后,必须把当前 `OsClient` 的 `TranslateProvider=LibreTranslate`、局域网基础地址 `TranslateUrl`、匹配的 `TranslateApiKey` 和超时写入 `sys_osclients`,并立即回读一致性;任一步失败都应终止安装。日志只显示 Provider 与 URL,禁止输出密钥。模型尚未完成时翻译能力可以暂时不可用,但不得拖住其它服务的安装。
73
+ 一键安装在 API Key 数据库预初始化成功、正式容器进入运行状态后,先启动平台 API,让共享升级租约中的幂等迁移补齐 `sys_osclients` 物理字段和 `diy_field` 元数据;API liveness 后立即回读 Upgrade31 的 4 个翻译物理字段,每秒一次且最多 15 秒,正常升级应首轮命中,镜像过旧或迁移失败应快速报错。只有数据库回读确认字段已存在,才能把当前 `OsClient` 的 `TranslateProvider=LibreTranslate`、Docker 内网 `TranslateUrl`、匹配的 `TranslateApiKey` 和超时写入并立即回读一致性。禁止在 API/Upgrade 启动前直接更新新字段,也禁止遇到 `Unknown column` 后由安装器伪造元数据。任一步失败都应终止安装。日志只显示 Provider 与 URL,禁止输出密钥。模型尚未完成时翻译能力可以暂时不可用,但不得拖住其它服务的安装。
74
+
75
+ 吾码公开镜像固定为 `registry.cn-hangzhou.aliyuncs.com/microios/libretranslate:1.9.6-microi1`。该镜像基于 1.9.6 固定摘要,仅把与 `requests 2.31.0` 不兼容的 `chardet 7.x` 固定为 `5.2.0`,构建必须同时通过 `pip check` 和将 warning 视为 error 的 `import requests`。安装脚本不得通过隐藏所有 Python warning 来掩盖依赖漂移。
51
76
 
52
77
  独立编排应使用 ASCII 目录和显式项目名 `docker compose -p microi-libretranslate`;只供平台 API 调用时,不默认开放 LibreTranslate 宿主机防火墙端口。需要公网调用时必须由运维显式配置 TLS、反向代理、访问控制、限流和强 API Key。
53
78
 
79
+ ## HTTP 与 MCP
80
+
81
+ 已登录 HTTP 入口固定为 `/api/Translate/TranslateText|Detect|Languages|TranslateFile|Suggest|Health`。Controller 必须用验证后的 Token 覆盖请求体 `OsClient`,不得接受 endpoint/key/header。
82
+
83
+ MCP 固定工具:`microi_translate`、`microi_detect_language`、`microi_list_translate_languages`、`microi_translate_file`、`microi_suggest_translation`、`microi_get_translate_health`。文件翻译需要 `confirmExecution=TRANSLATE_FILE`,建议写入需要 `confirmExecution=TRANSLATE_SUGGEST`;审计只记录长度、SHA-256、语言和输出模式,不记录文本、文件内容、本机路径或凭据。大文件结果落到新的绝对路径,不允许覆盖已有文件。
84
+
85
+ ## 安全硬上限
86
+
87
+ - 单条文本 5 万字符,单批最多 50 条/20 万字符,候选最多 10 个;
88
+ - 文件输入 20 MB、输出 25 MB;MCP 内联 Base64 额外限制为 2 MB;
89
+ - Provider URL 必须是无内嵌凭据的绝对 HTTP(S) 地址;禁用自动重定向;文件下载只允许与配置服务同源;
90
+ - 上游失败不回显响应体、堆栈、原文、内部 URL 或密钥;
91
+ - 语言缓存可作为节点级优化,但 Key 必须使用 `OsClient + URL + API Key 哈希`,不能含密钥明文,也不能作为共享事实源。
92
+
54
93
  ## 批量与后台任务
55
94
 
56
95
  大量内容翻译使用 Job/MQ/outbox。每条记录保存源文本版本与目标语言,只有源版本未变化时写回结果;事件用稳定 Id 幂等。后端 `setTimeout/Task.Run` 不是可靠后台任务。
@@ -71,10 +110,13 @@ LibreTranslate 是可选动态翻译供应商,不是 `diy_lang` 的替代品
71
110
  - [ ] 普通租户无法伪造 `OsClient`
72
111
  - [ ] 密钥、原始隐私文本和供应商堆栈不泄露
73
112
  - [ ] 长度、批量、超时、限流和费用上限生效
74
- - [ ] LibreTranslate 未选择时不部署;选择后 API Key 数据库预初始化成功且正式容器已启动
113
+ - [ ] 一路 Enter 默认部署 LibreTranslate 基础套餐 1;显式输入 0 才跳过
114
+ - [ ] API Key 数据库预初始化成功且正式容器已启动
75
115
  - [ ] LibreTranslate 内部端口未被安装脚本默认加入防火墙放行列表
116
+ - [ ] 翻译字段由幂等升级创建,安装器在 API 启动后最多 15 秒回读 schema 才写入配置
76
117
  - [ ] 缓存按租户/供应商/语言隔离
77
118
  - [ ] 多节点配置失效与批量幂等通过
119
+ - [ ] V8、HTTP、MCP 六类业务入口一致,运维面未被代理
78
120
 
79
121
  ### 复盘:模型下载期间健康检查误报成功导致 API Key 注册失败
80
122