diff --git a/CONTENT_SYNC.md b/CONTENT_SYNC.md index f7814f6..72ad2c8 100644 --- a/CONTENT_SYNC.md +++ b/CONTENT_SYNC.md @@ -2,13 +2,15 @@ ## ZBoard documentation migration — 2026-09-10 -ZBoard documentation is now authored in `docs/projects/zboard/`. Product introductions, installation, basic management, and plugin usage lead the navigation; contracts, design notes and historical acceptance records are separate reference sections. `zboard-document-migration.json` records each source, destination and source digest. +ZBoard documentation is now authored in `docs/projects/zboard/`. Product introductions, installation, basic management, and plugin usage lead the navigation; only current usage and integration references are published. Development plans, temporary contracts, schema snapshots and historical acceptance records are excluded. `zboard-document-migration.json` records each source, destination and source digest. -This migration uses ZBoard develop `37d1716c466ce16a1198399ac91c9de3e2c0c4f8` plus local documentation revisions. It is not a claim that every feature is in the published v0.0.1 artifact. Plugin runtime and marketplace documentation explicitly identifies the post-v0.0.1 development scope; shared-pool RAW editor additions are marked pending publication. Payments and other business extensions belong to plugins; the current payment extension interface is not implemented. Core and client evidence remains on the earlier baseline below. +This migration uses ZBoard develop `37d1716c466ce16a1198399ac91c9de3e2c0c4f8` plus local documentation revisions. It is not a claim that every feature is in the published v0.0.1 artifact. Plugin runtime and marketplace documentation explicitly identifies the post-v0.0.1 development scope; unpublished shared-pool RAW editor descriptions are excluded. Payments and other business extensions belong to plugins; the current payment extension interface is not implemented. Core and client evidence remains on the earlier baseline below. Public ZBoard documentation must be changed here, not copied back into the ignored product `docs/` directory. Product release packaging keeps its own release-note artifact under `.github/release-notes/`. -Verification: source and production-output checks passed for 97 Markdown pages, including every sidebar entry, internal link and anchor, JSON examples and rendered HTML. The migration also removes the product release workflow dependency on its local docs directory. +Initial migration verification: source and production-output checks passed for 97 Markdown pages, including every sidebar entry, internal link and anchor, JSON examples and rendered HTML. The migration also removes the product release workflow dependency on its local docs directory. + +Curation correction: removed 11 historical or superseded reference pages, rewrote rule compatibility and publication recovery as usage guides, and removed unpublished RAW editor notes. The manifest marks excluded sources rather than presenting them as live pages. ## Previous main audit — 2026-09-09 diff --git a/README.md b/README.md index 0a04a54..27fcaef 100644 --- a/README.md +++ b/README.md @@ -196,4 +196,4 @@ Documentation in this repository is published under the license declared by this ## ZBoard documentation ownership -ZBoard documentation is maintained in `docs/projects/zboard/`, including installation, plugin usage and technical references. The product repository retains only entry-point READMEs and build-owned release notes. Historical materials are labeled and grouped separately. See `zboard-document-migration.json` for migration provenance. +ZBoard documentation is maintained in `docs/projects/zboard/`, including installation, plugin usage and technical references. The product repository retains only entry-point READMEs and build-owned release notes. Development history is excluded from the public site. See `zboard-document-migration.json` for migration provenance. diff --git a/README.zh-CN.md b/README.zh-CN.md index d5d6176..90d0017 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -192,4 +192,4 @@ pnpm create:project -- \ ## ZBoard 文档维护 -ZBoard 的安装、插件使用与技术参考统一维护在 `docs/projects/zboard/`。产品仓库保留入口说明和构建使用的发布文案,历史资料在文档站单独归档。迁移来源记录在 `zboard-document-migration.json`。 +ZBoard 的安装、插件使用与技术参考统一维护在 `docs/projects/zboard/`。产品仓库保留入口说明和构建使用的发布文案,开发过程的历史资料不发布到文档站。迁移来源记录在 `zboard-document-migration.json`。 diff --git a/docs/.vitepress/navigation.ts b/docs/.vitepress/navigation.ts index b1c5444..cacb15f 100644 --- a/docs/.vitepress/navigation.ts +++ b/docs/.vitepress/navigation.ts @@ -171,22 +171,9 @@ const zboardSidebar: DefaultTheme.SidebarItem[] = [ page('插件开发', '/projects/zboard/plugins/development'), page('身份接口', '/projects/zboard/plugins/identity-reference'), page('插件治理', '/projects/zboard/plugins/governance'), - page('技术参考入口', '/projects/zboard/reference/'), - page('核心边界', '/projects/zboard/reference/core-baseline'), - page('数据模型', '/projects/zboard/reference/data-model'), - page('数据库迁移', '/projects/zboard/reference/database-migrations'), + page('配置与运行参考', '/projects/zboard/reference/'), page('节点配置交付', '/projects/zboard/reference/node-config-delivery'), - page('内核生命周期', '/projects/zboard/reference/node-kernel-lifecycle'), page('规则兼容性', '/projects/zboard/reference/managed-rule-compatibility'), - page('Mieru 内核契约', '/projects/zboard/reference/mieru-kernel-contract'), - ]), - group('设计与历史资料', [ - page('插件架构设计', '/projects/zboard/reference/plugin-system-design'), - page('插件市场设计', '/projects/zboard/reference/plugin-marketplace-design'), - page('0.0.1 发布记录', '/projects/zboard/reference/history/v0.0.1'), - page('核心 RC 验收记录', '/projects/zboard/reference/history/core-rc'), - page('历史发布清单', '/projects/zboard/reference/history/launch-checklist'), - page('历史路线图', '/projects/zboard/reference/history/roadmap'), ]), group('English', [ page('Installation', '/projects/zboard/guides/installation-en'), diff --git a/docs/projects/zboard/contributing/development.md b/docs/projects/zboard/contributing/development.md index 912f6c5..7658b71 100644 --- a/docs/projects/zboard/contributing/development.md +++ b/docs/projects/zboard/contributing/development.md @@ -67,8 +67,9 @@ create the first administrator and finish site initialization. The embedded SQL baseline is applied during startup. To run migrations without starting the HTTP service, use `scripts/migrate.ps1` or `scripts/migrate.sh`. -See [database-migrations.md](/projects/zboard/reference/database-migrations) before opening an existing -development database with a newer build. +Back up an existing database before running a newer build. Review the SQL migrations +shipped with that exact build; do not apply historical baseline-squashing procedures +to a published schema. ## Manual frontend startup @@ -128,8 +129,8 @@ Docker. The mixed workload defaults to 10 nodes, 1,000 subscriptions, 100,000 historical records, four concurrent readers and 100 events/second for 300 seconds. `DURATION_SECONDS`, `EVENT_RATE` and `READERS` select other workload profiles. The application and database share the 1 CPU / 1 GiB budget; the load generator -runs outside it. The [roadmap](/projects/zboard/reference/history/roadmap#资源和性能预算) defines latency and memory -budgets. Also verify exact accounting under replay and reordering, no OOM, +runs outside it. Set latency and memory budgets for the environment under test. +Also verify exact accounting under replay and reordering, no OOM, explained failures and a fully drained backlog. Real Zero revocation checks use isolated nodes and test credentials: @@ -142,8 +143,7 @@ ZERO_ARTIFACT_DIR=/path/to/verified-linux-zero-artifact \ The artifact directory must contain `zero` and its matching `verification.json`. Other scenarios are `exhaustion`, `group_change` and `recovery`. Verify data-plane access after revocation and publication recovery, including existing connections; -control-plane status or a mock SSH server alone is insufficient. See also -[node publication](/projects/zboard/reference/node-config-delivery#重跑-mysql-验证) for real MySQL checks. +control-plane status or a mock SSH server alone is insufficient. Keep raw logs, profiles, environment details, source/build hashes and per-run reports under the ignored `.codex-local-artifacts/acceptance/` directory. A dirty diff --git a/docs/projects/zboard/guides/index.md b/docs/projects/zboard/guides/index.md index 2f99837..8e77266 100644 --- a/docs/projects/zboard/guides/index.md +++ b/docs/projects/zboard/guides/index.md @@ -25,4 +25,4 @@ English installation instructions are available in [First installation](./instal | 排查连接和发布错误 | [故障排查](./troubleshooting) | | 清理节点 | [节点清理](./node-cleanup) | -日常管理还包括[控制台操作](./daily-operations)、[公告与邮件](./announcements-and-email)、[DNS 与证书](./dns-and-certificates)和[系统维护](./maintenance)。实现契约与开发流程集中在[开发参考](../reference/)中。 +日常管理还包括[控制台操作](./daily-operations)、[公告与邮件](./announcements-and-email)、[DNS 与证书](./dns-and-certificates)和[系统维护](./maintenance)。配置兼容性和发布排障见[运行参考](../reference/),插件接口见[开发指南](../plugins/development)。 diff --git a/docs/projects/zboard/guides/installation-en.md b/docs/projects/zboard/guides/installation-en.md index b25f73a..c9cc8be 100644 --- a/docs/projects/zboard/guides/installation-en.md +++ b/docs/projects/zboard/guides/installation-en.md @@ -100,7 +100,7 @@ Complete the site settings and create the first administrator. After initializat 5. **Activate a user subscription.** Use the basic order workflow to create an order for the plan and confirm it as an administrator. 6. **Connect a client.** In the user's account, choose the subscription format for the client and import its link. Make a connection, then check traffic usage in the console. -For a forwarding node or a shared upstream pool, continue with [network fronting](/projects/zboard/guides/network-fronting). Node installation and recovery are covered in the [node lifecycle guide](/projects/zboard/reference/node-kernel-lifecycle). +For a forwarding node or a shared upstream pool, continue with [network fronting](/projects/zboard/guides/network-fronting). Node installation and recovery are covered in the [node management guide](/projects/zboard/guides/node-management). ## Keep your data diff --git a/docs/projects/zboard/guides/installation.md b/docs/projects/zboard/guides/installation.md index d4c9587..11ee030 100644 --- a/docs/projects/zboard/guides/installation.md +++ b/docs/projects/zboard/guides/installation.md @@ -100,7 +100,7 @@ docker compose -f docker-compose.release.yml --env-file .env.release logs --tail 5. **开通用户订阅。** 使用基础订单流程,创建对应套餐的订单,由管理员确认后开通订阅。 6. **连接客户端。** 在用户账户中选择对应的订阅格式,将订阅链接导入客户端;连接后回到控制台查看流量用量。 -需要转发节点或共享上游代理池时,继续阅读[网络前置指南](/projects/zboard/guides/network-fronting)。节点安装和故障恢复见[节点生命周期说明](/projects/zboard/reference/node-kernel-lifecycle)。 +需要转发节点或共享上游代理池时,继续阅读[网络前置指南](/projects/zboard/guides/network-fronting)。节点安装和故障恢复见[节点管理指南](/projects/zboard/guides/node-management)。 ## 保存部署数据 diff --git a/docs/projects/zboard/guides/network-fronting.md b/docs/projects/zboard/guides/network-fronting.md index 5c40367..e117b8d 100644 --- a/docs/projects/zboard/guides/network-fronting.md +++ b/docs/projects/zboard/guides/network-fronting.md @@ -48,15 +48,11 @@ A 是固定目标的原始 TCP/UDP 转发器,B 执行协议解密、用户鉴 前置服务默认“直连落地”,不需要代理池。需要代理时,在「节点资产 → A 的详情 → 共享代理池」创建池,再在服务的“A 到 B 的路径”选择“使用 A 的共享代理池”。池配置是节点内资源,只能由同一 A 上的入口引用。 -::: info 代理池编辑说明的适用范围 -本页关于“回填配置、完整 RAW 转表单、读取已下发 RAW”的说明来自待发布的编辑器改动,尚不属于当前正式版或已推送的开发版。现有版本支持创建共享池及转发入口引用。 -::: - -新建时默认提供 URLTest 自动测速池。表单支持添加和编辑 Shadowsocks、VMess、VLESS、Trojan、Hysteria2、SOCKS5 或 Mieru 代理,以及测速组、选择组和多跳链路;可以修改成员顺序和最终出口 `target`。编辑已有池会回填原有节点、分组和凭据。点击“合并表单并查看 RAW”生成当前完整 Zero JSON;粘贴完整 JSON 后,可以直接保存,也可以点击“覆盖并转为表单”。覆盖前先检查标识、成员引用和循环,失败保留原表单。未展示的高级协议参数在表单往返时保持原样;仅在主动更换协议或连接安全类型时替换对应配置。这里只接受 Zero JSON,不导入 Clash/Mihomo YAML。 +新建共享池时可配置代理节点、测速组、选择组和多跳链路,并选择最终出口 `target`。配置使用 Zero JSON;保存前检查节点标识、成员引用和协议参数,具体格式见下方示例。 多条入口绑定各自的 B 协议端口,共用一份带 `pool-ID/` 前缀的代理图及测速状态,不会按入口复制 URLTest。每条入口独立生成匹配规则;选择直连的入口显式绕过池。代理池本身的内部认证不改变客户端协议在 B 完成握手和用户认证的事实。 -更新池会排队发布 A,所有引用入口一起生效;删除仍被引用的池会被拒绝。删除节点资产时自动清理其入口、关联及自有代理池,不执行 SSH 或供应商清理。保存池配置经过 Zero 校验,替换配置还会检查所有已引用入口的 TCP/UDP 兼容性,失败回滚。凭据加密保存,不下发给订阅客户端,列表和保存响应也不返回配置。管理员打开编辑器时,通过独立、带审计的接口读取原始配置和凭据;响应禁止缓存。只修改名称时保留原配置,修改代理参数时携带完整配置和修订号保存。旧的入口独立代理路径保留兼容,可切换成共享池或直连。 +更新池会排队发布 A,所有引用入口一起生效;删除仍被引用的池会被拒绝。删除节点资产时自动清理其入口、关联及自有代理池,不执行 SSH 或供应商清理。保存池配置经过 Zero 校验,替换配置还会检查所有已引用入口的 TCP/UDP 兼容性,失败回滚。凭据加密保存,不下发给订阅客户端,列表和保存响应也不返回配置。旧的入口独立代理路径保留兼容,可切换成共享池或直连。 完整路径示例: @@ -76,18 +72,5 @@ A 是固定目标的原始 TCP/UDP 转发器,B 执行协议解密、用户鉴 `url_test` 在多个候选出口中选择,`relay.proxies` 则按顺序组成多跳代理链,两者含义不同。保存时由 Zero 校验结构、协议字段与引用关系;具体出口还需要支持实际使用的 TCP/UDP 路径。在“TCP 与 UDP”模式下,已知不支持 UDP 的 HTTP CONNECT、VLESS Vision 和以 SOCKS5 为最后一跳的 UDP 代理链会被明确拒绝;仅 TCP 模式允许由内核校验通过的 TCP 路径。每个共享池的出口和组标签只添加一次池前缀;旧的独立路径仍按入口隔离。 -编辑时省略 `proxy_pool_id` 保留原池,提交 `0` 清除引用;直连时同时提交 `path_config: {}`。`parent_protocol_id` 是 B 的实际协议 ID,兼容旧字段 `endpoint_id`。`node_group_membership_changes` 与服务本身原子保存并创建凭据协调任务。代理池 API 是 `/api/v1/admin/node-proxy-pools`,GET 必须传 `node_id`,POST/PUT 配置字段为 `config`,保存响应不含凭据;更新携带 `revision`。管理员 `GET /api/v1/admin/node-proxy-pools/{id}/config` 返回 `pool` 元数据、原始 `config` 和带节点内标识前缀的 `compiled` 编译预览。编译预览不代表已下发。前置服务 API 继续使用管理员身份访问 `/api/v1/admin/network-entries`,更新携带当前 `revision` 防止覆盖其他管理员的修改。 前置线路保留 B 的 TLS/SNI/Reality 身份,以及 WebSocket 和 HTTP/2 的 Host;仅连接地址和端口替换为 A,避免长域名、CDN 或证书校验随入口地址发生变化。UDP 为每个客户端建立独立转发会话,避免多个用户向同一 B 协议发送数据时回包混淆。 - -## 回归验证 - -`TestSharedPoolCompilesOnceAndDirectEntryBypassesIt` 检查同池多个端口只生成一份代理图、直连规则绕过池、跨节点引用被拒绝及凭据不回显。`TestNetworkEntryRealTCPUDPForwarding` 在设置 `ZBOARD_ZERO_VALIDATE_BIN` 时运行真实 Zero,覆盖 TCP/UDP 原始转发、多跳路径、共享池,以及 B 的 VLESS 正确/错误凭据在直连和共享池路径上的认证结果;A 配置不得包含 B 的 VLESS 监听或用户 ID。 - -本地发布版 Zero 已通过 VLESS 认证用例。当前本地调试版在默认线程栈下运行该认证用例会栈溢出,设置 `RUST_MIN_STACK=16777216` 后通过;这项环境差异保留记录,本次未修改 Zero 内核。 - -### 代理池编辑与已下发 RAW(待发布) - -编辑器中的“读取节点配置”调用管理员接口 `GET /api/v1/admin/node-proxy-pools/{id}/runtime`,使用已保存的节点 SSH 配置读取 `/etc/zerodenet/current.json`。响应包含来源、读取时间、节点配置 SHA-256,以及此池的代理、分组和关联转发入口/路由;不返回其他代理池和监听协议的凭据。它是节点当前发布文件的快照,不是内核内存状态查询。 - -此读取有 20 秒超时和 8 MiB 文件上限,并记录审计、禁止缓存。节点无法连接或文件无法读取时明确报错,不用编译预览替代真实快照,也不影响当前编辑草稿。没有启用入口引用、或尚未发布时,快照可能不包含此池,此时 `present` 为 `false`。保存后要等节点发布成功,再重新读取快照。 diff --git a/docs/projects/zboard/plugins/development.md b/docs/projects/zboard/plugins/development.md index 69db4ce..92d3e79 100644 --- a/docs/projects/zboard/plugins/development.md +++ b/docs/projects/zboard/plugins/development.md @@ -1,6 +1,6 @@ # 插件开发与运维 -本期提供插件市场、插件管理、离线导入、三个前后台页面范围,以及可选服务端配置进程和身份提供方登录。核心业务所有权见 [设计](/projects/zboard/reference/plugin-system-design)。 +本期提供插件市场、插件管理、离线导入、三个前后台页面范围,以及可选服务端配置进程和身份提供方登录。核心业务所有权见 [插件范围与接口](/projects/zboard/plugins/governance)。 ## 配置宿主 diff --git a/docs/projects/zboard/plugins/index.md b/docs/projects/zboard/plugins/index.md index 0328d88..2f1e4ea 100644 --- a/docs/projects/zboard/plugins/index.md +++ b/docs/projects/zboard/plugins/index.md @@ -23,6 +23,6 @@ ZBoard 提供基础面板,在线支付及其他超出基础管理范围的能 当前开发版本支持扩展页面、插件自身配置、身份提供方和插件私有存储。安装时由宿主检查插件声明的能力和兼容性。 -支付插件的业务接口尚未开放,也未提供内置支付渠道;“通过插件扩展”描述的是产品边界,不表示任意插件能力已经可用。可用范围以[插件契约](../reference/plugin-system-design)和所用构建为准。 +支付插件的业务接口尚未开放,也未提供内置支付渠道;“通过插件扩展”描述的是产品边界,不表示任意插件能力已经可用。可用范围以[已开放接口](./governance)和所用构建为准。 插件市场是插件的查找和分发入口,需要由部署者配置市场目录与可信发布者。它不表示官方已经预置了一个包含所有扩展的公共市场。 diff --git a/docs/projects/zboard/reference/core-baseline.md b/docs/projects/zboard/reference/core-baseline.md deleted file mode 100644 index 54cc383..0000000 --- a/docs/projects/zboard/reference/core-baseline.md +++ /dev/null @@ -1,29 +0,0 @@ -# ZBoard 核心边界与复用基线 - -本文维护长期产品与工程约束。逐轮修复过程、跑测结果和环境记录保存在本地验收产物中。 - -## 已确定的方向 - -- 保留现有自用/小规模面板闭环,通过小步修复提高性能、稳定性与交互质量。 -- 核心包含用户、登录注册、节点/协议、基础订单、权益、订阅、流量、内核基础限制、文档公告及必要维护。 -- 核心定位是基础面板,在线支付及其他超出基础管理范围的能力统一通过插件扩展,不作为核心待补齐的内置功能。当前插件支持页面、自身配置、身份提供方和私有存储,并提供签名市场、管理和离线导入;各能力的实际开放范围见[插件边界](/projects/zboard/reference/plugin-system-design)。核心业务数据的写入仍由明确的专用服务负责。 -- [XBoard](https://github.com/cedar2025/Xboard) 对照业务流程;[X-Panel](https://github.com/xeefei/X-Panel) 参考基础/增值能力分离;[Typecho 插件实现](https://github.com/typecho/typecho/blob/master/var/Typecho/Plugin.php) 参考精简核心和扩展点。三者都不直接决定 ZBoard 的功能清单或性能结论。 -- 现有套餐/SKU、历史订单、权益和节点配置保持兼容,外围能力按真实依赖逐项隔离。未来 ZBoard 插件不能向 Zero Connector 引入支付、套餐或第三方业务语义。 - -## 已存在且应复用的实现 - -| 能力 | 当前证据 | 结论 | -| --- | --- | --- | -| 请求取消、旧响应隔离、卸载保护 | [useRemoteResource.ts](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/composables/useRemoteResource.ts)、[测试](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/composables/useRemoteResource.test.ts) | 已实现;检查页面是否正确接入,不另造框架 | -| 分页/游标表格与生命周期处理 | [useRemoteTable.ts](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/composables/useRemoteTable.ts)、[useCursorTable.ts](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/composables/useCursorTable.ts)、[生命周期测试](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/composables/remoteTableLifecycle.test.ts) | 已实现;逐页验证使用方式 | -| 路由懒加载 | [router/index.ts](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/router/index.ts)、[路由测试](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/router/routeLoadingPolicy.test.ts) | 已实现;不再列为待建设 | -| 流量分页与区间汇总分离 | [useTrafficUsageTable.ts](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/composables/useTrafficUsageTable.ts)、[后端测试](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/backend/internal/handler/traffic_usage_statistics_test.go) | 测试已验证无需总计的分页只执行一次 bucket 查询、summary 执行两次查询;不等于已测得生产耗时 | -| 图表独立加载、错误重试、筛选隔离 | [Traffic.test.ts](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/views/Traffic.test.ts) | 管理端和用户端复用既有加载与重试行为 | -| 订单状态转移与已支付幂等入口 | [handlers.go](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/backend/internal/handler/handlers.go)、[状态测试](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/backend/internal/handler/handlers_test.go) | 已有实现;并发和真实权益发放仍需按具体场景验证,不能称为完全缺失 | -| Fair Use 观测 | [FairUse.vue](https://github.com/zerodenet/zboard/blob/37d1716c466ce16a1198399ac91c9de3e2c0c4f8/frontend/src/views/FairUse.vue) | 已有观测功能;不能误称当前已经执行动态惩罚 | - -## 扩展与验证边界 - -核心独占订单、权益、计量和授权状态转移;外部能力通过明确的命令与查询调用。关键事务不等待可选外部动作,可靠通知根据真实需求设计恢复与幂等语义。 - -性能问题必须通过测量确认,不能仅凭同步调用或模块依赖判断瓶颈。验收预算见[路线图](/projects/zboard/reference/history/roadmap),可复跑方法见[开发指南](/projects/zboard/contributing/development#performance-and-stability-verification)。测试通过不等于生产容量、真实节点撤权或长稳已经达标。 diff --git a/docs/projects/zboard/reference/data-model.md b/docs/projects/zboard/reference/data-model.md deleted file mode 100644 index 898d872..0000000 --- a/docs/projects/zboard/reference/data-model.md +++ /dev/null @@ -1,201 +0,0 @@ -# zboard data model - -Scope and future extension ownership follow the [core and hardening baseline](/projects/zboard/reference/core-baseline). -The models below describe existing storage and compatibility constraints, not a -requirement to expand core commerce. Preserve historical orders and entitlements -during incremental hardening; future payment integrations belong to plugins. - -zboard is a modular monolith that combines subscription commerce with node operations. Product, entitlement, infrastructure and accounting data are deliberately separated so that editing a node or catalog entry cannot rewrite historical purchases. - -## Bounded self-service read projections - -Catalog pages may select an explicit purchase/renew/change/addon operation and -include or exclude a plan before counting and paging. The same operation scopes -the active SKU count and lowest-price primary SKU, including when the viewer is -an administrator. Cards consume this projection without per-card SKU requests. -The SKU detail collection is separately paginated; an optional anchor identifies -the page containing a deep-linked SKU within the same plan/operation/search -scope. A missing anchor is not replaced with another purchasable SKU. - -Subscription candidates use a server-side management filter and independent -pagination. An explicit subscription ID is resolved inside the authenticated -user scope, not searched only in a preview page. These are read projections: -they do not grant purchase eligibility, alter subscription ownership, change -historical entitlement snapshots or replace order-creation authorization. - -## Identity and installation - -- `users.email` is the normalized unique login identifier; `account_name` is a display name. -- Every login identity is a row in `users`. `is_admin` grants additional management capabilities to that user; it does not create a separate administrator identity or exclude the user from subscriptions, orders, traffic and tickets. -- Passwords are bcrypt hashes. Reusable API credentials live in `user_api_tokens`, which stores only a SHA-256 digest, a non-secret prefix and lifecycle timestamps. -- Optional registration email verification uses `registration_email_challenges` as a short-lived identity proof, not as a user or delivery record. Only a keyed digest of the code and requesting IP is persisted; successful user creation consumes the challenge and records `users.email_verified_at` in the same transaction. Disabling the public switch preserves the original direct-registration flow. -- `installations` is the one-time installation marker. Editable site and operational settings are mirrored into typed `system_configs`. Values are validated by their declared type, revisions provide optimistic concurrency, and rows marked `is_secret` are encrypted and redacted from API responses. - -## Commerce - -- `plans` owns entitlement policy: one required node group, traffic quota, speed/device/family limits, subscriber capacity, renewal policy, reset policy and traffic direction. Plans neither bind protocol endpoints directly nor define a second traffic multiplier. One plan revision protects those shared fields so an older editor cannot silently overwrite a newer save or publish-state change. -- `plan_skus` is the purchasable specification. Billing cadence (`periodic` or `one_time`), entitlement fulfillment (`plan` or `traffic_addon`), allowed operations (`purchase`, `renew`, `change`, `addon`) and renewal fulfillment are independent fields. A timed renewal explicitly chooses either `extend_only` or `extend_and_add_quota`; it never gains quota merely because its service term was extended. A one-time plan SKU may allow new purchase, renewal or plan change while inheriting the plan entitlement. Its day/month/year unit creates a fixed service term, while the `once` unit creates a permanent quota subscription whose traffic never resets and remains usable until exhausted; its only renewal effect is `add_quota_only`. Only an explicit traffic-addon SKU owns an additional traffic grant and is restricted to addon fulfillment. The legacy SKU type remains a compatibility projection rather than the source of these rules. -- `orders` references a SKU and stores a complete commercial snapshot, including the renewal effect used during fulfillment. Payment confirmation is admin/provider controlled; normal users cannot mark their own orders paid. -- `payment_events` reserves an idempotent provider-event boundary for signed payment integrations. -- `subscriptions` stores the granted commercial entitlement and selected node-group ID. Later plan or SKU edits do not rewrite its quota snapshot; changing membership of the referenced node group intentionally changes the endpoints delivered to every plan and subscription using that group. -- `subscription_members` represents actual family members; a numeric family limit alone does not grant membership. -- `subscription_tokens` stores a lookup digest plus encrypted token ciphertext so the owner can view and copy the complete URL again. Explicit rotation or revocation immediately invalidates previous URLs. The public URL is user-level and can aggregate multiple active subscriptions. -- `subscription_templates` stores operator-managed names, link slugs, availability, a constrained `renderer` identifier and versioned declarative customization for optional client-specific exports. Version 3 customization adds an explicit `rule` / `global` / `direct` initial mode, a local mixed HTTP/SOCKS inbound switch, sing-box system HTTP-proxy switching, typed DNS servers/cache/address-family/Fake-IP settings, and TUN settings to the existing native policy-group definitions, designated main group, final routing target and ordered mixture of reusable rule-set references and template-only remote shortcuts. Zero, Clash/Mihomo and sing-box full-configuration renderers project those fields into their native schemas. Every policy group receives all available protocol endpoints by default; optional RE2 include/exclude expressions match only the protocol configuration name, while explicit group references allow native nested selectors. Exported endpoints retain their operator-defined names without panel ID suffixes. Manual groups retain only renderer-valid special targets: Zero and Clash can expose `DIRECT` and `REJECT`, while current sing-box uses route rejection actions and does not emit the deprecated block outbound. The built-in probe default is `http://www.gstatic.com/generate_204`; the former exact HTTPS default is normalized to HTTP on startup without rewriting custom probe URLs. Rule-set bindings target a policy group, direct routing or rejection. Renderer implementation, response Content-Type, endpoint conversion and credential injection remain backend-owned. Advanced YAML (Clash) or JSON (Zero and sing-box) is parsed as data and deep-merged, never executed as Go template code. Dynamic root arrays can be replaced only when the documented generated-content marker is retained, and `$zboard:all-nodes` expands node names in member arrays. The administrator can also edit the complete credential-free versioned model as Raw JSON; valid Raw changes immediately reverse-project into the visual editor. Save, preview and live delivery all validate the final merged client structure, group members and route references. Version 1 and 2 records remain read-compatible and normalize to version 3. Selecting a template changes only response representation; the canonical manifest, endpoint authorization, per-subscription credentials and accounting inputs remain unchanged. The v0.0.1 baseline creates the non-executable renderer/customization boundary directly; a clean install does not create or archive legacy executable template bodies. -- `subscription_rule_sets` owns reusable renderer-specific remote source metadata: administrator name, output tag, URL, client-native format/behavior, update interval, availability and revision. A template reference owns only the action and list position, so editing the source updates every referencing template. `subscription_template_rule_set_bindings` is the foreign-key-backed reference index used for usage counts and deletion integrity; ordered customization remains the API composition boundary so reusable references and quick remote entries can be interleaved. Disabling a library record removes it from new selections without breaking existing subscriptions; deletion is rejected while any template references it. The v0.0.1 baseline creates the reusable rule-set tables and bindings in their final form without rewriting inline data. -- `protocol_credentials` binds one active subscription to one sellable endpoint. VLESS/VMess receive an independent UUID; Trojan/Hysteria2 receive an independent password; Shadowsocks receives an independent PSK and dedicated UDP/TCP listen/public port. `credential_id` remains the panel-side stable identifier, while `principal_key` is compiled into Zero's native managed-user entry for runtime attribution. Secrets are encrypted at rest. - -- Version 3 subscription-template customization owns an independently switchable local loopback mixed HTTP/SOCKS inbound plus optional DNS and TUN runtime settings; the mixed inbound and TUN cannot both be disabled. Zero receives native `runtime.dns`, `runtime.tun` and `mode`, and its visual DNS choices intentionally exclude unsupported plain TCP DNS. Clash/Mihomo receives native `mode`, `dns` and `tun` sections. sing-box receives stable typed DNS servers, TUN, route-mode projection and optional system-proxy activation. Standard Shadowrocket/v2rayN share-link feeds and Quantumult X `server_remote` resources remain node-resource protocols: they cannot carry client-global DNS, TUN, mode or policy settings, so the UI declares that boundary instead of accepting settings that their wire formats would discard. Every generated full-configuration document remains directly runnable without GUI-side repair. -- Public ZNet Sink template delivery and the canonical native manifest base64-encode their already validated JSON documents while administrative preview remains readable JSON. This is representation-level concealment only: subscription authorization still depends on the 256-bit token, TLS, revocation and rotation. Clash and sing-box remain in their client-native representations. Invalid or revoked public subscription tokens return a no-store redirect to the private `subscription_camouflage_url` system setting, falling back to the installation's public site URL; other API 404 responses keep their machine-readable contract. - -## Operations and node groups - -- `provider_accounts` is the reusable external-supplier boundary. A provider - key declares adapter capabilities such as `dns.records`, - `certificate.public` or `payment.checkout`; each configured account owns an - encrypted, redacted credential and verification lifecycle. Domain resources - reference the account, but DNS, certificates and future payment channels - retain separate typed tables and invariants rather than sharing an opaque - provider-resource JSON table. -- `managed_dns_records` stores one handwritten FQDN, explicit A/AAAA target, - selected node and Cloudflare desired/observed state. The target remains an - operator-owned value rather than a live pointer to the node. An on-demand, - admin-only address-candidate projection can read literal node fields, resolve - their hostnames and inspect global interface addresses through an already - verified SSH channel. It returns only publicly routable IPv4/IPv6 candidates, - never mutates a record and never enrolls SSH trust. The create UI may fill an - empty field from the first candidate, but operator edits and existing record - values are never replaced by refreshes; choosing another candidate is an - explicit action. Zboard discovers the longest matching Zone, refuses to - overwrite an unowned remote record unless takeover was explicit, records - provider operations, and distinguishes API synchronization from public-DNS - observation. The create API may accept one A and one AAAA value together, but - persists them as two independently owned records. A background observer - retries public resolvers until each synced record is visible; it never repeats - the Cloudflare write merely because propagation is pending. Mutable target, - address, TTL and proxy policy use optimistic concurrency and resynchronize - after editing. Deletion removes local desired state without calling the provider; old remote records must be managed explicitly in the provider console. Identity changes use explicit delete-and-recreate. A node remains - an infrastructure asset and does not acquire a single canonical domain. -- `managed_certificates` explicitly owns either a verified Cloudflare provider - account for DNS-01 or a canonical node webroot for HTTP-01. DNS-01 does not - require public TCP port 80. HTTP-01 Webroot does not bind a second listener, - and verifies resolvable targets on TCP port 80 before issuance because that - is part of the ACME HTTP-01 contract. A missing IPv6 route on the control - plane is treated as an unobservable family rather than proof that the remote - node is down; concrete refusal and timeout errors still block issuance. - Certificate display name, ACME contact, Webroot and renewal policy are - revision-protected mutable fields; node, domains, environment and challenge - identity require a new certificate asset. DNS-01 first uses the operating - system plugin package and falls back to an isolated Certbot Python virtual - environment when the distribution does not publish that package. Legacy - standalone certificates remain renewal-compatible but cannot be newly - created. -- Deletion of infrastructure resources is local and transactional. SSH, CA or - provider API availability is not a prerequisite. Node deletion removes owned - protocols, credentials, entries, pools, certificate/DNS management records and - membership links. Surviving entry nodes receive queued configuration withdrawal. - Historical traffic, administrative task and audit facts are retained. -- Certificate deletion unlinks protocols and stops panel renewal without - revoking CA certificates or deleting node files. DNS deletion leaves the - provider record intact. Provider deletion removes local DNS records and - detaches certificates with automatic renewal disabled. -- Protocol and entry deletion clears memberships automatically. Runtime removal - is queued and may remain pending while the node is offline. Actual running - operations are still serialized or rejected to avoid concurrent recreation. -- The offline node cleanup utility separates stop/disable from explicit uninstall. - It is downloadable, included in binary archives and installed alongside new - managed Zero installations. See `node-cleanup.md` for exact paths and scope. - -- `nodes` is an independent VPS asset. It can exist without a protocol and owns lifecycle state, encrypted management/report credentials, communication mode, runtime status, enablement, version and synchronization timestamps. -- SSH client authentication selects password or private key. Server identity verification is automatic: an empty fingerprint is enrolled after the first successful SSH handshake, a recorded fingerprint is always enforced, and an administrator must explicitly reset trust after confirming a legitimate VPS reinstall or host-key change. -- SSH login identity and system privilege are separate node settings. `ssh_privilege_mode=none` requires a root login for managed system changes; `sudo` supports passwordless or password-based sudo; `su` requires a separately encrypted root password. Privilege passwords are sent only on the SSH session stdin and are never embedded in remote commands, operation output or audit details. -- Browser SSH terminals remain a node-operations capability. The browser receives only a short-lived, single-use terminal ticket; the backend keeps the encrypted SSH credential, enforces same-origin WebSocket upgrades, proxies a bounded PTY session, and audits session metadata without recording terminal contents. -- SSH reachability, Zero installation, applied runtime configuration, Zero process health, authenticated Connector activity and trusted traffic reporting are separate operational states. A successful SSH test, protocol-config upload or Connector delivery must not imply the other states are healthy. -- Current host resources are an on-demand administrative projection owned by the node asset. CPU cores/load averages, memory, root-filesystem capacity and host uptime are read through the already verified SSH channel and are not persisted as Zero session statistics or exposed without administrator authentication. This projection is deliberately named host resources rather than protocol load. -- `protocol_endpoints` is the sellable runtime network resource and must reference exactly one node when saved. Its configuration is template-like in the administration workflow: an operator may copy it into an independent inactive draft or switch its carrier node, while the saved runtime instance retains one unambiguous node for credentials, publishing and accounting. A node switch updates credential placement, reallocates dedicated Shadowsocks ports when necessary, and publishes only the active runtime sides of the move. The endpoint separates listen and public ports, encrypted server configuration, deliverable client configuration and the sole traffic multiplier. Optional protocol configuration and tags are JSON. Endpoint mutations are classified before server configuration encryption: management, billing and delivery changes remain control-plane updates, while active runtime and credential-placement changes publish only the nodes whose running configuration changes. -- VLESS and VMess transport selection is endpoint template configuration, not a separate protocol resource. Raw TCP is represented by the absence of an additional carrier; managed WebSocket and gRPC choices write matching server and subscriber-client fields, and every renderer converts those canonical values to its native representation. VLESS Reality is an endpoint transport capability, not a separate sellable protocol resource, and Zero `0.0.15` restricts it to raw TCP. Zboard generates a matching X25519 key pair and short ID, encrypts the private key only in the endpoint server configuration, and publishes only the public key, selected short ID, server name and client fingerprint. Maintained one-click scenario presets choose the SNI and client fingerprint together with fresh key material; operators may still adjust the result before saving. The generated Zero, Clash and sing-box representations preserve their renderer-native Reality fields; managed subscription UUID replacement does not rewrite the transport configuration. -- `parent_protocol_id` is a same-node, acyclic self-reference for a single protocol stack parent. -- `node_groups` groups sellable endpoints. `node_group_endpoints` is the many-to-many relationship; endpoint group membership is never stored as comma-separated IDs. One node-group revision protects descriptive fields, status and membership together so concurrent administrators cannot silently replace each other's delivery boundary. `protocol_endpoints.sort_order` is the global client-delivery order. `network_entries.delivery_sort_order` gives forwarding entries an independent position in the same global order; an unset position inherits its landing endpoint position until explicitly ordered. `GET/PUT /api/v1/admin/subscription-delivery-order` uses typed `protocol:` and `entry:` keys, requires the complete list and its current version, and never publishes Zero. Custom forwarding names replace the landing display name while preserving TLS identity, credentials and billing ownership. -- A node-group editor may resolve one bounded, ID-only protocol-endpoint filter snapshot for bulk selection. The snapshot is transient operator input, not a second persisted group or dynamic membership rule; saving still writes explicit `node_group_endpoints` rows. Large saves validate and upsert membership in bounded batches and delete only removed links instead of deleting and recreating the complete relationship set. -- The protocol-endpoint editor uses a separate endpoint-centric membership command. It submits only added or removed node groups together with each group's loaded revision. The transaction locks those groups, rejects stale revisions, appends a new endpoint after the existing group order, removes only the requested relationship, and increments only groups whose relationship actually changed. Copying a protocol endpoint does not inherit memberships implicitly because that would widen a delivery authorization boundary. -- A plan and the resulting subscription reference one node group. Subscription delivery joins through that group and only returns active endpoints on enabled, online nodes. -- Subscription delivery normalizes endpoint order before rendering. Active subscriptions are aggregated by expiry then ID; credential-backed endpoints keep their owning subscription's group position, and legacy endpoints use the earliest applicable subscription group. ZNet Sink, Clash / Mihomo and sing-box renderers all consume that same ordered endpoint slice, including policy-group members, so one saved business order produces the same relative client order across formats. -- Saving a protocol endpoint does not inherently publish a node. Name, client address or port, global delivery order, tags and traffic multiplier are applied without a Zero restart. Runtime fields publish the current node only while the endpoint was or becomes active; carrier-node moves publish the previous and target sides only when each side has an active runtime to remove or add. The publisher still compiles every active endpoint and active subscription credential on an affected node into one complete Zero runtime configuration, records the desired SHA-256, validates it with the installed binary, atomically switches the generation, restarts Zero, checks the local control socket and waits for a fresh authenticated Connector event. Runtime compilation is ordered by stable endpoint identity rather than client-delivery order, so later unrelated publications do not change runtime hashes after a business reorder. -- `protocol_deployments` records desired and applied configuration hashes. A deployment is successful only after the running node passes local health and Connector-event verification; validation or verification failure restores the previous generation and environment. The explicit deploy action is a retry of the same full publish path, not a single-file staging action. -- The runtime-log API merges `protocol_deployments`, `node_operations` and `tasks` into one newest-first operational view while retaining each source record and its error/output. `audit_logs` remains a separate security and business-change trail. - -## Traffic and quota accounting - -- `flow_usages` is the idempotent cursor for Connector-delivered `flow.updated` and `flow.completed` events. Live events charge only the new cumulative delta; the completed event settles any missing final delta. -- Protocol business load is derived from active `flow_usages` seen within the last two minutes. `active_flows` counts current flow IDs and `active_users` counts distinct subscription owners, so allocated credentials are never presented as currently connected people. Administrators see the aggregate on every protocol endpoint; subscribers see only aggregate load for endpoints reachable through their own currently usable node groups. No other user's identity, credential, host detail or traffic record crosses that boundary. -- `protocol_endpoints.managed_principal_ready` gates subscription-specific Trojan and Hysteria2 credentials on the successfully published kernel generation. Older kernels continue to receive and advertise the endpoint fallback credential; a failed publication never exposes credentials that the running node has not accepted. -- Zero uses a generic Webhook event sink with a disk-backed outbox and an opaque authorization header. Every event is authenticated with the node Connector credential. Lifecycle events update Connector activity; flow events are mapped through the native `principal_key` and its protocol credential. Request-provided user IDs are never trusted for billing. The legacy signed node-report endpoint and the old heartbeat/command routes remain compatibility-only. -- Native speed and device policies are projected only when a subscription has one active protocol credential. Copying a subscription-wide limit to multiple independent Zero processes would multiply its allowance. Cross-node speed/device aggregation, directional or weighted traffic calculation and quota balance therefore remain panel-owned until an acknowledged distributed policy protocol exists; `quota_remaining_bytes` is not emitted by zboard. -- Zero `0.0.15-rc.4` adds attributable `principal_key` support to - `MieruUserConfig`. Zboard gates Mieru by the selected or actually installed - node version: older nodes reject creation, re-enabling and publication while - retaining records for disable/delete recovery; rc.4 and newer generate one - encrypted password and principal per subscription. A successful - fallback-bearing migration publication is followed under the same node lock - by a fallback-free publication. Only after both validate, activate, pass - health checks and receive Connector confirmation does - `mieru_principal_ready` switch subscription delivery. `credential_id` - remains panel-side metadata and is never emitted into Zero configuration. - The contract and rollout behavior are documented in - `docs/mieru-kernel-contract.md`. -- The native access contract is an explicit staged boundary: `ZBOARD_ZERO_KERNEL_CONTRACT=legacy` keeps the latest stable GitHub tag only as the unattended batch default, while an operator may explicitly select any published stable or prerelease tag. The selected release uses its immutable `zero-linux-x86_64.tar.gz` GNU artifact or musl artifact plus exact same-name `.sha256`; musl resolution accepts both the current `zero-linux-x86_64-musl.tar.gz` contract and the historical release-owned `zero-v-linux-x86_64-musl.tar.gz` contract. The backend re-resolves every selected version rather than accepting a client URL; an explicit older target also requires a separate downgrade confirmation. Connector serialization follows the selected or actually installed Zero version independently of that access switch: releases through `0.0.15-rc.1` receive the historical `api_key_env` plus `push` contract, while `0.0.15-rc.2` and later receive the controller-neutral Webhook contract with opaque `headers`, the complete `/api/zero/events` URL and a durable outbox. Configuration-only publication probes the node first so it cannot reuse a stale desired-version contract. A trusted-directory historical versioned musl file remains a bounded fallback when the corresponding older GitHub Release has no usable musl pair. `native-local` enables managed users only with an explicit `ZBOARD_ZERO_LOCAL_VERSION`; it still resolves the exact `zero-v-linux-x86_64-musl.tar.gz` plus `.sha256` from the trusted artifact directory and never substitutes a GitHub release. Synchronizing zboard alone does not publish or upgrade the local kernel. -- `traffic_calc_mode` selects upload plus download (`0`), upload only (`1`) or download only (`2`). -- Billed traffic is calculated with integer thousandths: `selected_bytes * protocol_multiplier_milli / 1_000`, rounded up. -- `traffic_records` stores the direction policy and protocol multiplier snapshot, so later endpoint changes never alter historical accounting. -- Human-facing traffic history is a read-only projection over `traffic_records`: details can group by minute, hour or UTC day while retaining user, subscription, node and multiplier dimensions. The node-series projection applies the same authorization and optional filters, then intentionally groups away user/subscription identity to answer node-capacity questions and produce a descending node-total ranking; it never creates a second accounting fact. -- Account usage pages carry bounded `facets.nodes` and `facets.subscriptions` reference maps for their own rows. A top-node chart ranking is not a complete directory. Subscription labels are independently restricted to the authenticated owner; deleted or incorrectly associated foreign subscriptions remain explicit missing references. Node references expose only ID, name, region and lifecycle status, never host or credential fields. Page rows and reference maps are replaced atomically by the client. -- Reconciliation scopes raw traffic totals by the selected subscription IDs before aggregation, not by the raw row's user ID: a misattributed record remains visible as an accounting fact for its subscription. Issue-page counts reuse summary counts and page rows reuse their joined totals. Cursor seeks on usage buckets retain the complete cursor bucket before aggregation; the raw ID must not be used to cut a bucket before its `MIN(id)` and sums are computed. Request cancellation propagates through these read queries, and no accounting writes or persisted aggregate tables are introduced. -- Grouped usage supports an independent `view=usage_summary` projection with `total`, `aggregates`, `bucket` and `as_of`. Its sum/count reads run in one database transaction. Current clients request live pages with `include_totals=false`, receiving explicit null totals/aggregates; they do not fabricate zero or reconstruct whole-range totals from visible rows. The separate statistics snapshot is keyed by authorization/filter/range/bucket, not cursor or page size, and is refreshed on scope changes or an explicit refresh. The UI displays its timestamp and keeps paging usable while statistics are pending or fail; live rows and an older labelled statistics snapshot are not a single cross-request snapshot. -- The server coalesces concurrent identical statistics/trend reads and reuses completed display snapshots for at most two seconds from query start, with 32 entries per projection and per handler instance. Errors are not cached. All account authorization and trend subscription references are read live. Grouped pages with totals expose `statistics_as_of` (null when totals are omitted); summary/trends retain `as_of`. Repeated refresh within this interval may return the same timestamp. These snapshots never participate in settlement, balance, revocation or ledger verification. -- Account subscription filter options use the paged self-service subscription reader, with `q` matching plan/SKU names or an exact subscription ID before count/offset/limit, always inside the authenticated owner. Historical subscriptions are selectable without an active-status restriction. A URL-selected ID is resolved independently, not replaced by a preview row. Trend responses no longer load a subscription directory by default; `include_subscriptions=true` is an explicit deprecated compatibility opt-in only, never used by current UI filters. -- `(node_id, report_id)` provides retry idempotency and `(node_id, nonce)` prevents replay. -- `quota_events` is the auditable allocation/usage ledger. Subscription counters remain the fast balance projection and can be reconciled against traffic and quota events. - -## Background work - -- `tasks` contains common locking, retry and progress fields. Creation uses an idempotency key and resolves the JSON scope into concrete targets before commit. -- `task_items` stores independently retryable recipients or quota targets. Batch progress is therefore derived from concrete items rather than an opaque JSON list. -- Node-group membership mutations persist a `node_group_reconcile` task in the same database transaction. Its first item revokes active subscription credentials outside the current group membership and ensures credentials for current endpoints. Node items are included only for changed endpoints whose protocol stores per-subscription credentials and whose group currently has usable active subscriptions; an empty node scope still records the credential reconciliation without publishing unrelated runtime configuration. This keeps `Subscription -> NodeGroup -> ProtocolEndpoint` as the authorization boundary while making failed credential or node work visible and retryable. -- Quota tasks lock each subscription, reject reductions below already-used traffic, write an idempotent `quota_events` adjustment and queue affected node configurations for reconciliation before completing the item. -- Email tasks are disabled by default. They require encrypted SMTP credentials and either STARTTLS or implicit TLS. Completed recipients are skipped on retry; SMTP delivery remains at-least-once if the process stops after a remote server accepts a message but before the item status commits. -- `email_templates` owns revisioned plain-text presentation content, not delivery state. The fixed `user.registered` template can be enabled or disabled but not deleted; operational templates are reusable drafts. Creating a task snapshots the subject, body, template provenance and current site identity into `tasks.content`, then recipient variables are resolved from the target `users` row at execution time. Template edits therefore cannot rewrite queued or historical messages. -- SMTP verification has two explicit side-effect levels: connection mode completes DNS/TCP, TLS, optional authentication and `NOOP` without sending mail; delivery mode sends one test message to the administrator-specified recipient. Neither endpoint returns SMTP credentials. -- The admin task summary is a read model derived from `tasks` and `task_items`: it exposes task-state counts plus active target progress without creating a second queue or duplicating task ownership. -- Execution is initiated through the admin API or the management page. The lock expiry permits recovery of a task left running by a terminated process. - -## Relationship summary - -```text -nodes -> protocol_endpoints -provider_accounts -> managed_dns_records -> nodes -protocol_endpoints <-> node_group_endpoints <-> node_groups -plans -> node_groups -plans -> plan_skus -users -> orders -> plan_skus -orders -> subscriptions -> node_groups -subscriptions -> protocol_credentials -> protocol_endpoints -subscriptions -> subscription_members -users -> subscription_tokens; subscription_templates -> export representation -protocol_credentials -> flow_usages -> traffic_records -subscriptions -> quota_events -tasks -> task_items -email_templates -> tasks (content snapshot only) -``` - -## Migration ownership - -The embedded SQL under `backend/migrations` is the production schema source of truth. Before the first public release, `0001_init.up.sql` directly expresses the complete v0.0.1 resource model: plans reference one node group, node groups own explicit protocol-endpoint membership, subscriptions retain their granted plan/SKU/node-group snapshot, and no legacy plan-to-endpoint or access-group tables are created. Startup records applied files in `schema_migrations`; GORM `AutoMigrate` is not used in production startup. - -Existing databases from the former v0.0.1 development chain are accepted only after they reached its terminal migration. Startup verifies the final schema signature, removes only the empty legacy template archive and renames the stale access-group index. Previously applied migration rows remain as rollback compatibility metadata even though their SQL files are no longer shipped; a fresh database records only `0001_init.up.sql`. Partial and unversioned non-empty schemas are rejected. After v0.1.0 is released, the baseline becomes immutable and all schema changes use append-only migrations. See [database-migrations.md](/projects/zboard/reference/database-migrations). - -### 管理员分配订单 - -管理员通过 `POST /api/v1/admin/orders` 为指定用户创建待付款订单。选择商品规格后,可以覆盖 `payable_amount`(整数分);未指定时使用规格价格。`amount_cents` 保留规格原价,低于原价的差额记录为 `discount_amount`,高于原价时优惠为零。用户订单列表展示最终应付金额。 - -`orders.assigned_by`、`assignment_note` 保存分配人和原因,创建订单与 `order.assign` 审计日志在同一事务中提交。详情只向管理员公开分配记录。`assignment_fingerprint` 不对外返回;管理员 ID 与请求 UUID 派生唯一交易号,用来防止重复请求创建多笔订单。重复请求返回原订单当前状态,不重新开通。 - -分配只生成 `pending` 订单,即使应付金额为零也不自动开通。收到付款并确认后,复用现有履约事务,为订单所属用户开通或续费订阅、分发其显式授权范围内的凭证,实际收入按该订单最终实收金额统计。 diff --git a/docs/projects/zboard/reference/database-migrations.md b/docs/projects/zboard/reference/database-migrations.md deleted file mode 100644 index 94c1b25..0000000 --- a/docs/projects/zboard/reference/database-migrations.md +++ /dev/null @@ -1,128 +0,0 @@ -# Database migrations - -> Historical baseline note: v0.0.1 has been publicly released. The pre-public v0.0.1/v0.1.0 numbering and baseline-squashing policy below document earlier development work, not permission to rewrite a published schema. For an existing installation, verify the migration behavior of the exact source and target builds. First-time installation is covered in the [installation guide](/projects/zboard/guides/installation-en). - -Zboard embeds its SQL schema in the backend binary and records applied files in -`schema_migrations`. Production startup does not use GORM `AutoMigrate`. - -## Historical v0.0.1 baseline policy - -`v0.0.1` is the development baseline before the first public release. The -repository therefore contains one migration pair: - -- `backend/migrations/0001_init.up.sql` -- `backend/migrations/0001_init.down.sql` - -The up migration directly creates the complete current business schema and -seeds the 13 system configuration entries and three built-in subscription -templates. It does not retain development-only `ALTER TABLE`, temporary -rewrite tables, data backfills, legacy executable-template archives or -environment-specific auto-increment counters. - -Until `v0.1.0` is released, new schema work must update this baseline and its -clean-database verification. Do not add `0002` merely to preserve an -unreleased development step. - -## Fresh database - -Point the backend at an empty MySQL 8 database and start it normally, or run: - -```bash -cd backend -../scripts/migrate.sh -``` - -```powershell -cd backend -../scripts/migrate.ps1 -``` - -The runner creates `schema_migrations`, applies `0001_init.up.sql`, validates -the final table/column/index signature and records one applied version: -`0001_init.up.sql`. - -Do not manually create application tables or insert a migration record. - -## Existing pre-squash v0.0.1 database - -An existing development database can be retained only when the previous build -already completed the former chain through -`0032_subscription_policy_group_targets.up.sql`. - -On first startup with the squashed build, the runner: - -1. confirms the original `0001_init.up.sql` record exists; -2. refuses a multi-entry history that never reached the terminal development - migration; -3. validates all final business tables, selected critical column types and - cursor/concurrency indexes; -4. removes the empty legacy subscription-template archive table and renames - the old node-group index to its final resource name; -5. adds the nullable managed-certificate provider ownership, Webroot path, - provider index and provider foreign key when an earlier v0.0.1 development - database does not yet contain them; -6. adds the non-null `protocol_endpoints.mieru_principal_ready` publication - gate when it is absent; -7. leaves the already-applied development rows in `schema_migrations` so the - immediately previous development binary remains usable for rollback. - -This path does not rerun the baseline and does not rewrite normal business -rows. An archive table containing rows blocks finalization so an operator can -export or deliberately remove that data first. - -The retained rows are compatibility metadata only. Their SQL files are not -shipped in the squashed build and a fresh database records only -`0001_init.up.sql`. A database created from the squashed baseline cannot be -opened with an older pre-squash binary. - -Before replacing a development build, back up: - -- the MySQL database; -- the credential-encryption key; -- the currently deployed source or image needed for rollback. - -If the database has a partial migration history, start the previous -development build and finish its migrations before using the squashed build. -If a non-empty schema has no migration history, recreate it or perform an -explicitly reviewed data migration; the runner will not guess its origin. - -## Verification - -For a fresh database, verify: - -```sql -SELECT version FROM schema_migrations ORDER BY version; -SELECT COUNT(*) FROM information_schema.tables - WHERE table_schema = DATABASE() AND table_name <> 'schema_migrations'; -SELECT COUNT(*) FROM system_configs; -SELECT COUNT(*) FROM subscription_templates; -``` - -Expected baseline results are one migration record, 43 business tables, -13 system configuration rows and three built-in templates. - -For a retained development database, also verify that application row counts -and the previous applied-history rows remain unchanged across the upgrade, and -that the obsolete -`subscription_template_legacy_archives` table and -`uk_access_groups_code` index are absent. - -## Durable node publication queue - -The baseline includes `node_config_publishes`. For an existing development -schema, startup creates this table additively from the same embedded DDL. -SQLite upgrades include it in the model inventory. Existing business rows are -preserved; pending publication rows are included in cross-database migration. -The due-work index is `idx_node_publish_due`. - -## Policy after v0.1.0 - -Once `v0.1.0` is released: - -- `0001_init.up.sql` becomes immutable; -- every released schema change receives a new ordered up/down migration; -- previously published migration content and filenames are never rewritten; -- destructive changes require an explicit backup, compatibility and rollback - plan; -- clean-install schema and sequential-upgrade schema must be verified as - equivalent before release. diff --git a/docs/projects/zboard/reference/history/core-rc.md b/docs/projects/zboard/reference/history/core-rc.md deleted file mode 100644 index 299d214..0000000 --- a/docs/projects/zboard/reference/history/core-rc.md +++ /dev/null @@ -1,70 +0,0 @@ -# Core hardening RC freeze — 2026-09-06 - -::: info 历史资料 -此页保留迁移前的发布或工程记录,供维护者追溯;不作为当前安装教程、产品定位或功能可用性说明。使用入口见[项目介绍](/projects/zboard/)。 -::: - -This release candidate freezes the current self-use panel scope: authentication, -users, orders, subscriptions, nodes, traffic accounting, announcements and public -documents. Online payment channels and a plugin runtime remain deferred. - -## Included fixes - -- Persist node configuration publication with transactional enqueue, retries and - process recovery. Revoke expired/exhausted subscriptions and reconcile group changes. -- Preserve order fulfillment idempotency and accounting consistency under concurrent - requests and replayed traffic reports. -- Reduce SQLite accounting and reporting contention, bound display statistics caches, - and accelerate raw event-spool reads without changing accounting authority. -- Fix administration detail lifecycle, subscription-rule forms, order interactions - and theme consistency. - -## Verification and release boundary - -The standard 300-second mixed workload passed on 1 CPU / 1 GiB with 1,000 -subscriptions, 100,000 historical records, 100 unique events per second and -concurrent administration reads. Traffic-page p95 was 231 ms, trends p95 was -686 ms and sampled peak working set was 163.2 MiB. Final expected, ledger and -subscription totals matched; the event spool drained completely. - -Real isolated Zero tests passed expiry, quota exhaustion, single-node group -switching, and SSH publication failure followed by publisher-process recovery. -Backend tests/vet and targeted race checks passed. These performance and real-node -measurements predate the final dependency security updates below. Per-run evidence is retained outside version control. Reproducible methods are -documented in the [development guide](/projects/zboard/contributing/development#performance-and-stability-verification); -the remaining acceptance limits are listed below. - -This is a candidate for self-use and small deployments. The 24-hour soak, -500-events-per-second burst and broader multi-node/full-process recovery matrix -are not complete. These remain follow-up acceptance work; this RC does not claim -the full stable-release checklist is complete. - -## Release security corrections - -The final push surfaced dependency advisories that the earlier functional acceptance -had not assessed. Source-level `govulncheck` identified calls to vulnerable SSH, JWT, -HTTP/TLS and telemetry dependencies. The RC updates the Go toolchain to 1.26.8 within -the existing 1.26 series and upgrades affected backend dependencies to patched versions. -Docker and development-script toolchain baselines are kept in sync. - -After these updates, full backend tests, vet and the pure-Go SQLite checks passed. -Source-level `govulncheck ./cmd/zboard` reported zero reachable vulnerabilities and -zero additional imported-package vulnerabilities. One advisory remains at module -level for unused OpenPGP code; the panel does not import that package. - -Frontend audit findings concern development/test tools and compiler dependencies. -A production Rollup module inventory confirmed that happy-dom, Vitest, nanoid, -PostCSS and the Vue SFC compiler are absent from emitted browser chunks. The runtime -Docker stage contains static browser assets and Go/Rust binaries, not Node.js tools. -Development dependency advisories remain follow-up maintenance, not a claim of a -clean dependency manifest. Two unquoted OpenAPI descriptions were also corrected -after release CI identified YAML flow-mapping schema errors. - -## Upgrade and rollback - -Back up the database and credential encryption key together before upgrading. -Startup applies the persistent publication queue and SQLite reporting/access -schema reconciliation. Preserve the event-spool directory across restarts. -For rollback, restore the previous image with its matching pre-upgrade database -backup; retain the original spool and backup until reconciliation is complete. -Do not run two panel versions against the same writable database during rollback. diff --git a/docs/projects/zboard/reference/history/launch-checklist.md b/docs/projects/zboard/reference/history/launch-checklist.md deleted file mode 100644 index 78a6e76..0000000 --- a/docs/projects/zboard/reference/history/launch-checklist.md +++ /dev/null @@ -1,151 +0,0 @@ -# zboard v0.1.0 release checklist - -::: info 历史资料 -此页保留迁移前的发布或工程记录,供维护者追溯;不作为当前安装教程、产品定位或功能可用性说明。使用入口见[项目介绍](/projects/zboard/)。 -::: - -> Status: planned first public release. The current development baseline is `v0.0.1`. - -Scope follows the [core and hardening baseline](/projects/zboard/reference/core-baseline). -The core must work without plugins. Existing flows require regression evidence; -online payment channels and a plugin runtime are deferred extensions, not release gates. - -## 0. Version validation - -- `VERSION` is `v0.1.0` -- `backend/internal/version/version.go` has `Version = "v0.1.0"` -- Go baseline validation: - - `backend/go.mod` contains reviewed `go` and `toolchain` directives - - CI and the Docker builder use the same toolchain family - - `go mod tidy`, tests, vet, and build complete without changing tracked files -- Before release, run and record: - - `./scripts/verify-env.ps1` or `./scripts/verify-env.sh` - - Confirm output includes: - - `Go mod baseline` - - `Go toolchain baseline` - - the checked-in Go toolchain baseline - -## 1. Environment preparation - -- Set `ZBOARD_GOROOT_FALLBACK` only when CI or the operator uses a preinstalled - SDK outside `PATH`; never record a workstation-specific absolute path here. -- Ensure scripts: - - `scripts/ensure-go-env.ps1` - - `scripts/ensure-go-env.sh` -- Env check: - - `./scripts/verify-env.ps1` - - `./scripts/verify-env.sh` -- Datastore: MySQL 8+ -- Production configuration contains independent random values for: - - `ZBOARD_MYSQL_ROOT_PASSWORD` - - `ZBOARD_MYSQL_PASSWORD` - - `ZBOARD_JWT_SECRET` - - `ZBOARD_CREDENTIAL_ENCRYPTION_KEY` -- No `generate-` or `choose-` placeholder remains in the deployment environment. -- For a new database, `/setup` completed with the intended site name, public URL, - registration policy, and a unique first-administrator password. -- A second `POST /api/v1/setup/install` is rejected with HTTP 409. -- Nodes can be reached via SSH (`ssh` host/port + authentication) -- Each node has an independently verified OpenSSH SHA256 host-key fingerprint. -- Database backup and secret backup together can decrypt node credentials in a restore rehearsal. - -## 2. Local start and smoke tests - -### Start - -```powershell -cd scripts -./start-dev.ps1 -WithFrontend -StopWhenDone -``` - -```bash -cd scripts -./start-dev.sh --with-frontend --stop-when-done -``` - -### Health checks - -- `GET /healthz` => service response -- `GET /readyz` => readiness response -- `GET /api/v1/version` => `v0.1.0` -- `GET /api/v1/system/info` => system info -- `GET /api/v1/auth/me` => auth check - -## 3. Business feature validation - -1. User / Auth - - `POST /api/v1/auth/register` - - `POST /api/v1/auth/login` - - `GET /api/v1/auth/me` -2. Nodes, protocol endpoints and node groups - - `POST /api/v1/nodes` - - `PUT /api/v1/nodes/:id` - - `POST /api/v1/nodes/ssh/test` - - `POST /api/v1/nodes/:id/report-credential` - - Verify invalid signature, expired timestamp, reused nonce, and duplicate report ID behavior. - - `POST /api/v1/admin/protocol-endpoints` - - `PUT /api/v1/admin/protocol-endpoints/:id` - - `POST /api/v1/admin/protocol-endpoints/:id/deploy` - - `POST /api/v1/admin/node-groups` - - Verify password/private-key authentication, automatic first-connection host-key enrollment, mismatch rejection and explicit trust reset. - - Verify plans select a node group and cannot bind protocol endpoints directly. -3. Orders and subscription - - `GET /api/v1/plans` - - `POST /api/v1/orders` - - `POST /api/v1/admin/orders/:id/pay` (administrator confirmation) - - Verify duplicate confirmation grants entitlements only once, cancellation - races preserve a valid terminal state, and ordinary users cannot confirm orders. - - Existing internal pay-callback routes retain administrator authentication; - they are not public payment-provider callbacks. - - `GET /api/v1/subscriptions` - - `POST /api/v1/traffic/report` - - `GET /api/v1/traffic/summary` - - Verify traffic replay does not double-count usage; restart recovery does not - lose committed accounting; expired/exhausted subscriptions and revoked - credentials stop authorizing access, including on the node. - - Verify failed node publication cannot be presented as applied configuration. -4. Admin - - `GET /api/v1/admin/users` - - `POST /api/v1/admin/users` - - `PUT /api/v1/admin/users/:id` - - `GET /api/v1/admin/dashboard` - -Core hardening evidence: - -- Record browser checks for login/register, orders, subscription access, usage, - announcements and public documents, including failures and retries. -- Record backend tests/vet, frontend tests/build and OpenAPI validation. -- Meet the [resource and performance gates](/projects/zboard/reference/history/roadmap) - with a reproducible workload and a 24-hour stability report; attach measurements, - not only pass/fail statements. -- Record behavior and resource use with optional capabilities disabled. Core - accounting and node authorization must remain correct. - -## 4. Docker deployment validation - -- Build the release image from a clean checkout with the locked frontend dependencies. -- Start MySQL and zboard through the supported Compose deployment. -- Confirm startup fails closed when required production secrets are missing or placeholders are used. -- Back up the database before replacing the application image. -- Verify `/healthz`, `/readyz`, `/api/v1/version`, login, orders, and subscriptions. -- Restore the previous image and database backup in a rehearsal environment and record the result. -- Kubernetes deployment and Kubernetes-driven rollout APIs are outside the v0.1.0 support scope. - -## 5. Release packaging - -- `git tag -a v0.1.0 -m "release v0.1.0"` -- `git push origin v0.1.0` -- GitHub Actions release job succeeds: - - Docker image published - - Release metadata includes: - - `version` - - `commit` - - `build time` - -## 6. Emergency notes - -- If you hit local network issues while fetching Go and need to continue, temporarily set: - - `ZBOARD_ALLOW_STALE_GO_VERSION=1` -- Before continuing the next release run: - - confirm the configured Go executable works - - confirm `scripts/verify-env.ps1` or `verify-env.sh` passes diff --git a/docs/projects/zboard/reference/history/roadmap.md b/docs/projects/zboard/reference/history/roadmap.md deleted file mode 100644 index 5fcefda..0000000 --- a/docs/projects/zboard/reference/history/roadmap.md +++ /dev/null @@ -1,88 +0,0 @@ -# zboard implementation roadmap - -::: info 历史资料 -此页保留迁移前的发布或工程记录,供维护者追溯;不作为当前安装教程、产品定位或功能可用性说明。使用入口见[项目介绍](/projects/zboard/)。 -::: - -> 历史规划说明:本文保留首个公开版本发布前的阶段划分、编号方案和验收目标。`v0.0.1` 已公开发布;下文将 `v0.1.0` 视为“首个公开版本”的表述,以及阶段完成状态,不代表当前发行状态。可用版本以 [Releases](https://github.com/zerodenet/zboard/releases) 为准,当前使用入口见[文档导航](/projects/zboard/guides/)。性能预算是验收目标,不是已测容量。 - -> 当前开发版本固定为 `v0.0.1`。在所有公开发布条件满足前,不因为内部阶段变化而提升版本号;首个对外发布版本仍为 `v0.1.0`。 - -> 2026-09-05 方向对齐:以 [核心能力与加固基线](/projects/zboard/reference/core-baseline) 为产品和工程约束。已有基础闭环采用小步修复与性能加固;内部服务为未来插件保留边界。在线支付和插件运行时不属于当前基础版发布前置条件。下表和历史完成项不代替当前提交的实测验收。 - -> 按[开发指南中的性能与稳定性验收方法](/projects/zboard/contributing/development#performance-and-stability-verification),依次验证计量基准、1C1G 混合负载、真实节点撤权和 24 小时长稳;每次运行的原始证据保存在版本库外。 - -## 版本原则 - -- 从当前状态到公开发布前的全部研发、加固和验收工作都属于 `v0.0.1`。 -- 工程基线、安全边界、业务闭环、可运营性和发布验收是工作阶段,不是版本号。 -- 各阶段允许交叉、回退和重复验证,不通过版本升级制造虚假进度。 -- 候选构建使用 Git commit、构建时间和流水线编号标识,不创建中间 `v0.0.x` 阶段版本。 -- 只有全部发布门禁通过后,才将版本从 `v0.0.1` 切换为 `v0.1.0` 并发布。 -- Kubernetes 清单和集群级滚动升级不在当前支持范围内;通过已验证 SSH 管理单台节点的 Zero 安装、配置、升级和回滚属于节点运维能力。 - -## v0.0.1 工作阶段 - -| 阶段 | 状态 | 目标 | 主要交付 | 退出条件 | -| --- | --- | --- | --- | --- | -| A. 工程基线 | 已完成 | 建立可重复验证的仓库基线 | 统一版本;锁定 Go/Node/pnpm;前端锁文件;后端测试;OpenAPI 校验;CI;Docker-only 范围收口 | 后端 test/vet/build、前端 typecheck/build、OpenAPI lint 和 Docker Compose 配置校验通过 | -| B. 安全与信任边界 | 进行中 | 消除公开部署前的高风险默认行为 | 禁止默认生产管理员;强制安全 JWT 密钥;日志脱敏;SSH 凭据安全存储与主机密钥校验;节点上报鉴权、签名和幂等 | 弱默认配置不能进入生产;敏感信息不落日志;伪造或重复上报被拒绝 | -| C. 可信业务闭环 | 已有实现,待加固验收 | 加固订单、订阅和流量的现有闭环 | 管理员确认订单幂等;订阅生效/过期/耗尽;节点客户端配置交付;流量对账 | 下单、管理员确认、获取订阅、使用流量和额度扣减的正常/异常端到端测试通过 | -| D. 可运营性 | 待完成 | 建立定位、恢复和回退能力 | 结构化日志、指标和审计;备份恢复;Docker 蓝绿切换与回退演练;故障诊断;端到端冒烟测试 | 可观测、可备份、可恢复、可回退,并保留演练证据 | -| E. 低资源部署 | 进行中 | 单机 1 vCPU / 1 GiB 可持续运行 | 有界查询和响应;低并发连接池与后台任务;移除无消费者的运行依赖;MySQL/SQLite 方言隔离;SQLite 部署档案 | 1C1G 压测和长稳验收达标,MySQL/SQLite 语义测试一致 | -| F. 公开发布验收 | 待完成 | 冻结并验证 `v0.1.0` 公开契约 | API/配置兼容性冻结;安全审计;安装与升级文档;候选镜像;真实环境验收 | 发布清单全部通过,无阻断级缺陷 | - -这些阶段描述责任边界和验收顺序,不代表自动推进。安全与可信数据链路是业务闭环验收的前置条件,但修复期间项目版本仍保持 `v0.0.1`。 - -## 当前进度 - -### 已完成 - -- [x] 将仓库版本统一为 `v0.0.1`,明确 `v0.1.0` 为首个公开版本。 -- [x] 固定 Go 1.26.8、Node.js 22.23.0、pnpm 11.9.0。 -- [x] 增加 pnpm 锁文件、Vue 类型检查和可复现安装。 -- [x] 增加后端关键辅助逻辑与版本元数据测试。 -- [x] 建立后端、前端和 OpenAPI CI 门禁。 -- [x] 移除 Kubernetes 资源、升级 API、前端入口和脚本。 -- [x] 保留 Docker Compose、Docker 镜像和单二进制部署路径。 -- [x] 移除固定管理员密码和 JWT 回退密钥,生产环境强制显式安全配置。 -- [x] 对日志中的数据库 DSN 脱敏,并拒绝生产 root 账号和已知弱数据库口令。 -- [x] 使用 AES-GCM 加密节点 SSH 密码或私钥,首次连接自动登记 SHA256 主机密钥,后续固定校验并要求显式重置信任。 -- [x] 为节点签发独立流量上报凭据,增加 HMAC 签名、五分钟时间窗、nonce 防重放和 report ID 幂等约束。 -- [x] 对订单结算和同用户续期加锁,阻止重复续期与已支付订单状态回退,并统一收口过期/耗尽订阅状态。 -- [x] 协议端点发布同时校验服务端与客户端 JSON,避免订阅继续交付旧客户端配置。 -- [x] 为用户、订单、协议配置和凭据生命周期补齐审计写入,并提供管理员分页查询界面。 -- [x] 将每笔可信流量扣减归属到实际订阅,并提供用户/管理员订阅级对账结果。 - -### v0.0.1 剩余工作 - -1. 补齐订单、订阅、配置交付和流量扣减的代码级闭环测试与异常路径。 -2. 加固管理员订单确认、取消与权益发放的一致性,逐步提取统一内部服务;保持当前内部回调的管理员认证。支付渠道签名接入和外部回调来源认证由未来支付插件实现,不作为基础版缺口。 -3. 补齐可观测性、备份恢复、Docker 回退演练和公开发布证据。 -4. 按 [Zero 节点生命周期](/projects/zboard/reference/node-kernel-lifecycle) 实现探测、安装、整机配置编译、校验、启动、健康确认与可回滚升级;不得把“SSH 可连接”或“配置文件已上传”显示成内核健康。 -5. 完成下述 1C1G 与 SQLite 迁移门禁;在双数据库语义测试通过前,SQLite 不作为受支持的生产数据库。 -6. 按核心基线逐项闭环前后端缺陷,记录复现、根因、回归与性能对比;按实际依赖隔离 Fair Use 等非核心能力,保持基础计量、限制和既有配置有效。 -7. 随业务修复建立窄服务与类型化错误,避免 handler 相互调用和扩展直接写核心数据;现阶段不建设插件加载器、市场或通用事件总线。 - -## 1C1G 与 SQLite 迁移门禁 - -### 资源和性能预算 - -- 单机档案以 1 vCPU、1 GiB RAM 为硬上限;应用与 SQLite 的稳定工作集目标不超过 700 MiB,并至少给操作系统和突发请求保留 300 MiB。 -- 普通分页和详情接口在代表性数据集上的服务端 p95 不超过 250 ms;受控的流量趋势/对账接口 p95 不超过 1 s,单次数据库查询不得依赖反向代理超时结束。 -- 列表、图表和导出都必须有服务端分页、游标或明确结果上限。节点流量序列默认最多 8 个节点、约 12,000 个点;选择单节点后才允许扩大时间窗口。 -- 低资源默认数据库连接池为 8 个打开连接、2 个空闲连接;固定并发后台任务必须改成共享预算或可配置并发,不能让多个四路 worker 在 1 核上相互争抢。 -- 前端首屏不得同时触发所有重聚合接口;独立视图按优先级渐进加载,前端只负责有界结果的展示转换,不承担全量数据聚合。 - -### SQLite 推进顺序 - -1. 引入数据库驱动和方言能力边界,先保持 MySQL 行为不变;时间分桶、错误分类、锁、upsert、索引检查和表元数据查询不得继续散落在 handler/datastore 中。 -2. 将迁移拆成 MySQL 与 SQLite 两套可审计路径,为 SQLite 明确启用 WAL、`busy_timeout`、外键约束,并限制写并发。 -3. 对 CGO 与纯 Go SQLite 驱动做独立构建、迁移、备份恢复和基准验证,再固定生产驱动;驱动选择不得只以“本机能编译”为验收依据。 -4. 在 CI 中对 MySQL 与 SQLite 执行同一套订单、订阅、流量扣减、幂等和分页语义测试;任何方言分支都必须有回归覆盖。 -5. 增加 1C1G 容器档案、代表性数据生成器和至少 24 小时长稳测试,记录 RSS、CPU、连接数、查询 p95/p99、错误率及数据库文件增长。 - -## v0.1.0 发布门禁 - -`v0.1.0` 不是按日期或阶段自动产生的版本。只有上述剩余工作和 -[v0.1.0 release checklist](/projects/zboard/reference/history/launch-checklist) 全部完成,才允许修改版本号、创建 tag 和推送公开镜像。 diff --git a/docs/projects/zboard/reference/history/v0.0.1.md b/docs/projects/zboard/reference/history/v0.0.1.md deleted file mode 100644 index 048bde2..0000000 --- a/docs/projects/zboard/reference/history/v0.0.1.md +++ /dev/null @@ -1,19 +0,0 @@ -# ZBoard v0.0.1 - -::: info 历史资料 -此页保留迁移前的发布或工程记录,供维护者追溯;不作为当前安装教程、产品定位或功能可用性说明。使用入口见[项目介绍](/projects/zboard/)。 -::: - -首个统一编号正式版,与 Zero Core 和 ZNet Sink v0.0.1 配套。旧 Release 与 tag 已按项目所有者要求清理。 - -- 提供用户、订阅、节点、订单、流量与规则管理,以及内核配置发布和事件计量。 -- 支持新 Zero v0.0.1 的通用 Connector、托管用户与 Mieru 用户归属;移除版本编号重置后失效的协议门槛。 -- 前置入口集成到协议服务,支持可选的节点共享代理池;落地协议授权必须显式分配。 -- 管理员可为指定用户创建待付款订单并调整应付金额,付款确认后开通权益,保留分配审计与防重复提交记录。 -- 资源删除不再依赖 SSH 或外部服务连通性,提供独立 Shell 工具清理节点残留。 -- 商品列表和详情展示商品描述,修复复制协议时的节点组选择。 -- 发布 Linux amd64 二进制包、Docker 镜像及镜像离线包,附 SHA256SUMS。 - -Docker 镜像:`ghcr.io/zerodenet/zboard:v0.0.1`,正式版同时更新 `latest`。同名版本重建后,部署端需要重新拉取镜像并重建容器。 - -升级前请备份数据库、配置与持久化目录。旧编号内核版本高于新 v0.0.1,切换内核需明确选择目标并允许降级。现有自动化测试与构建验证不等同于 24 小时长稳、500 events/s 突发或完整多节点故障恢复验收。 diff --git a/docs/projects/zboard/reference/index.md b/docs/projects/zboard/reference/index.md index e1a144c..6aef63e 100644 --- a/docs/projects/zboard/reference/index.md +++ b/docs/projects/zboard/reference/index.md @@ -1,21 +1,10 @@ -# 技术参考 +# 配置与运行参考 -这里面向维护者和集成开发者,说明面板的数据、配置交付与内核接口。首次部署请从[安装教程](/projects/zboard/guides/installation)开始。 +这里补充当前使用中需要的规则兼容性和配置发布说明。项目定位、安装和插件入口见 [ZBoard 首页](/projects/zboard/)。 -- [核心能力与边界](/projects/zboard/reference/core-baseline) -- [数据模型](/projects/zboard/reference/data-model)与[数据库迁移](/projects/zboard/reference/database-migrations) -- [节点配置交付](/projects/zboard/reference/node-config-delivery)与[内核生命周期](/projects/zboard/reference/node-kernel-lifecycle) -- [规则兼容性](/projects/zboard/reference/managed-rule-compatibility) -- [Mieru 内核契约](/projects/zboard/reference/mieru-kernel-contract) -- [插件开发](/projects/zboard/plugins/development)与[身份接口](/projects/zboard/plugins/identity-reference) +- [规则导入与客户端兼容性](./managed-rule-compatibility) +- [配置发布与故障恢复](./node-config-delivery) +- [系统维护与数据库切换](../guides/maintenance) +- [插件开发接口](../plugins/development)与[身份接口](../plugins/identity-reference) -## 设计与历史资料 - -以下资料保留设计依据和当时的验收范围。计划项不代表当前版本已经实现,历史版本编号也不作为新安装的版本要求。 - -- [插件架构设计](/projects/zboard/reference/plugin-system-design) -- [插件市场设计](/projects/zboard/reference/plugin-marketplace-design) -- [0.0.1 发布记录](/projects/zboard/reference/history/v0.0.1) -- [核心 RC 验收记录](/projects/zboard/reference/history/core-rc) -- [历史发布检查清单](/projects/zboard/reference/history/launch-checklist) -- [历史路线图](/projects/zboard/reference/history/roadmap) +开发方案、迁移过程记录、临时契约和验收日志不作为公开使用文档。版本发布信息请查阅 [ZBoard Releases](https://github.com/zerodenet/zboard/releases)。 diff --git a/docs/projects/zboard/reference/managed-rule-compatibility.md b/docs/projects/zboard/reference/managed-rule-compatibility.md index f138ad9..99816f5 100644 --- a/docs/projects/zboard/reference/managed-rule-compatibility.md +++ b/docs/projects/zboard/reference/managed-rule-compatibility.md @@ -1,43 +1,30 @@ -# Managed rule import and client compatibility +# 规则导入与客户端兼容性 -ZBoard imports independent rule sets, stores their matching conditions, and publishes stable client-specific URLs. Routing actions and ordering belong to subscription templates. +规则集保存匹配条件,订阅模板负责选择规则、配置动作和排列顺序。导入前先确认规则文件的格式和目标客户端。 -## Importing dler-io/Rules +## 选择导入来源 -Use files under `Clash/Provider/` with source format `auto` (recommended) or `clash_classical`. Auto detection accepts Provider YAML, line-oriented Classical rules, domain lists, CIDR lists and canonical JSON. An explicitly selected format is never silently changed. +导入 Clash Provider 时可使用自动识别或明确选择 `clash_classical`。支持 Provider YAML、Classical 文本、域名列表、CIDR 列表和规范 JSON;明确选择格式后不会自动换成另一种格式。 -Supported Classical matchers are `DOMAIN`, `DOMAIN-SUFFIX`, `DOMAIN-KEYWORD`, `IP-CIDR`, `IP-CIDR6`, `PROCESS-NAME` and `PROCESS-PATH`. Process names and paths retain case and spaces. Unknown matchers fail with their position rather than being dropped. +Clash Classical 支持 `DOMAIN`、`DOMAIN-SUFFIX`、`DOMAIN-KEYWORD`、`IP-CIDR`、`IP-CIDR6`、`PROCESS-NAME` 和 `PROCESS-PATH`。未知条件会报错,不会静默丢弃。 -`sing-box/1.12/Head.conf` and `Rule.conf` are configuration fragments, not independent rule sets. They must be adapted in subscription templates; they are not importable as Provider files. Files containing only comments, such as the current `Media/MOO.yaml`, are rejected with an empty-source explanation. A rejected synchronization retains the previous source. +应选择独立规则集文件。完整客户端配置、配置片段和只有注释的空文件不能作为独立规则集导入。同步失败时保留之前成功导入的内容。 -## Storage and publishing +## 按客户端使用 -Existing network-only documents retain the Zero Rule IR v1 shape and continue to compile to ZRS. ZBoard stores client-specific matchers in an optional `client_rules` extension, outside the Zero IR `rules` array: +| 规则内容 | Zero | Clash / Mihomo | sing-box | +| --- | --- | --- | --- | +| 域名、IP / CIDR 条件 | 可生成 ZRS | 可生成规则源 | 可生成规则源 | +| 进程名称或进程路径 | 不支持 | 保留进程条件 | 保留进程条件 | -```json -{ - "version": 1, - "rules": [{ "type": "domain_suffix", "value": "example.com" }], - "client_rules": [{ "type": "process_name", "value": "Example.exe" }] -} -``` +包含进程条件的规则集不能绑定 Zero 模板,也不会生成删掉部分条件的 ZRS。如果规则集已经用于 Zero 模板,更新时加入进程条件会被拒绝,原内容保留。 -This extended document is internal ZBoard storage, not a new Zero kernel contract. Client-only sources may have `rules: []`, but the combined document must contain at least one matcher. Their database format is `managed_client_rules`. +Clash 模板使用 Classical YAML 地址;包含客户端专属条件的规则集,其复制出的公共地址使用 sing-box 源格式。应通过对应订阅模板获取适合客户端的配置。 -Clash YAML/text and sing-box source exports preserve both arrays. sing-box uses separate rule objects for different condition types, preserving the imported set's OR semantics. The sing-box artifact cache has a new format revision so previously generated files cannot bypass the corrected encoder. +## 常见问题 -Zero currently cannot evaluate process rules. A source containing any client rules does not produce ZRS, is excluded from the Zero template picker, and is rejected if explicitly bound to a Zero template. Updates adding client rules to a source already bound by Zero templates are rejected before changing its content. There is no partial ZRS export that silently drops process conditions. +- **导入失败**:检查是否选择独立规则集、格式是否正确、内容是否为空,以及错误提示中的条件位置。 +- **Zero 模板无法选择规则集**:检查是否包含进程名称或路径条件。 +- **客户端没有命中进程规则**:确认客户端及平台支持进程识别。转发其他设备的流量并不能获取那台设备上的进程身份。 -The copied public URL for client-only sources selects sing-box source format. Clash templates automatically select the Classical YAML endpoint. Actual process detection remains a client/platform capability; forwarding a remote device's traffic does not provide its process identity. - -## Verification - -Normal backend tests cover parsing, canonical round trips, client exports, public downloads, Zero compatibility guards and rejected updates. To validate a checked-out external Provider corpus with a real sing-box binary: - -```sh -ZBOARD_RULE_PROVIDER_TEST_DIR=/path/to/Rules/Clash/Provider \ -ZBOARD_SING_BOX_VALIDATE_BIN=/path/to/sing-box \ -go test ./internal/handler -run TestManagedRuleProviderRepositoryCompatibility -v -``` - -Run from `backend/`. The optional corpus test performs no network downloads. It imports each nonempty YAML source, round-trips through Clash YAML, and compiles the sing-box output to SRS. +继续阅读[订阅配置与流量](../guides/subscriptions-and-traffic)。 diff --git a/docs/projects/zboard/reference/mieru-kernel-contract.md b/docs/projects/zboard/reference/mieru-kernel-contract.md deleted file mode 100644 index 383e5d5..0000000 --- a/docs/projects/zboard/reference/mieru-kernel-contract.md +++ /dev/null @@ -1,77 +0,0 @@ -# Mieru native principal attribution prerequisite - -Zboard does not modify the Zero kernel as part of Mieru endpoint-credential -support. Zero `0.0.15-rc.4` implements the required matched-user -`principal_key` propagation. Older releases accept Mieru users by password but -cannot attribute their traffic to the correct subscription, so Zboard keeps -Mieru disabled on those nodes. - -## Required Zero contract - -The rc.4-or-newer contract used by Zboard must: - -1. add a stable `principal_key` field to each `MieruUserConfig`; -2. preserve the matched Mieru user identity after password authentication; -3. attach that user's `principal_key` to the authenticated session and every - emitted flow event, using the same semantics as the existing native managed - protocols; -4. reject duplicate or empty principal keys and configurations that contain a - password without an attributable principal; -5. keep username/password client compatibility explicit. If a client requires - username, Zero or the renderer may use `username=password`; username must - not become the accounting identity; -6. add kernel tests covering two Mieru users on one listener, successful - authentication, isolation, reconnects, and correct principal propagation to - completed flow events. - -Managed speed/device policy fields should be added only if Zero can enforce -their semantics consistently with other native managed users. They are not a -precondition for identity attribution. - -## Zboard activation gate - -For a target node running Zero rc.4 or newer, Zboard: - -- include Mieru in `protocol_credentials`; -- generate one encrypted password and `principal_key` per active subscription; -- compile those users into the endpoint's Mieru server configuration; -- render only the requesting subscription's password; -- migrate active subscriptions, validate with the installed Zero binary, and - republish affected nodes. - -The public protocol capability contract advertises `0.0.15-rc.4` as the -minimum Zero version. The backend checks the selected or actually installed -version rather than a panel-wide flag. On older nodes it rejects new Mieru -endpoints, re-enabling and publication; subscription generation excludes -retained Mieru records. Existing records remain visible and can be disabled or -deleted safely. - -## Zboard rollout gate - -`native-local-mieru` remains a backwards-compatible contract name. A reviewed, -locally pinned rc.4-or-newer artifact under the normal `native-local` contract -enables the same Mieru behavior automatically. GitHub-managed nodes are gated -by the selected or probed installed version. - -Under that contract Zboard compiles Mieru users with -`username=password`, `password`, and `principal_key`. Template save and preview -execute `zero validate` from the checksum-pinned artifact. Node publication -then executes the installed Zero validator, atomically activates the -generation, checks process/control health and waits for a Connector event. -Only after that complete publication succeeds is -`protocol_endpoints.mieru_principal_ready` set and subscription delivery -switched from the endpoint credential to the requesting subscription's -credential. Validation or activation failure retains the previous generation -and endpoint credential. The first successful migration generation retains the -fallback user under a bounded `migration:endpoint:` principal so existing -clients are not cut off before the database readiness switch. Zboard -acknowledges but never bills those temporary flows. While holding the same -node publication lock, Zboard then performs a second full publication without -the fallback user. Readiness and subscription delivery switch only after this -fallback-free generation also passes validation, activation, health and -Connector confirmation. If cleanup fails, Zero rolls back to the compatibility -generation and the endpoint remains unready, so the shared credential cannot -remain accepted behind a falsely ready state. - -`credential_id` is deliberately absent from every emitted Zero user object. It -is a stable panel/database identifier, not part of the Zero runtime schema. diff --git a/docs/projects/zboard/reference/node-config-delivery.md b/docs/projects/zboard/reference/node-config-delivery.md index 6d9f1a0..0fc4cad 100644 --- a/docs/projects/zboard/reference/node-config-delivery.md +++ b/docs/projects/zboard/reference/node-config-delivery.md @@ -1,73 +1,29 @@ -# 节点配置发布与恢复 +# 配置发布与故障恢复 -自动发布使用数据库表 `node_config_publishes`,不依赖外部消息队列。 -每个节点仅保留一条待发布状态;执行时根据当前已提交数据生成完整配置。 +在面板保存协议服务、网络前置、共享代理池或订阅权益后,相关节点的配置进入发布队列。保存成功表示面板已记录修改,节点需要完成发布后才会使用新配置。 -## 提交与执行 +## 查看发布结果 -订单确认及跨节点组切换、订阅凭据到期(包括读取触发的过期处理)、 -流量耗尽、配额任务调整、协议端点直接变更 -以及内核操作完成后的 Mieru 就绪发布, -会在业务事务内写入发布请求。请求写入失败时业务事务回滚,调用方可以重试。 -启动时的凭据兼容处理也持久化发布请求,失败会阻止启动完成。 -这些路径不在业务事务内等待 SSH。 +1. 在协议服务中查看发布状态和最近一次发布记录。 +2. 排队或重试中的节点尚未完成本次更新;检查错误说明。 +3. 发布完成后,分别确认节点进程、配置和 Connector 上报状态。 +4. 涉及用户权限或线路变更时,再通过客户端验证实际连接。 -服务启动主动检查待办;最多四个线程发布,空闲时由一个 5 秒定时器轮询。 -数据库以节点为主键合并请求;新版本到达时,正在执行的版本完成后还会再发布。 -已支付订单的重复确认不会生成新请求。 +SSH 可连接、进程运行和节点配置已生效是不同状态。不能仅凭其中一项判断整个服务正常。 -## 失败与重启 +## 发布失败时 -- 失败保留待办、错误和次数,按 5、10、20 秒等间隔退避,间隔上限 5 分钟。 - 未成功的任务继续重试,不以达到次数上限为由丢弃。 -- 工作线程领取任务时设置唯一标记和 3 分钟租约,执行期间定期续租。 - 进程异常退出后,其他线程只能在租约到期后接手;正常退出会取消执行并保留失败待办。 -- 单次自动发布限时 2 分钟。SSH 的 TCP 连接和完整握手共用最多 12 秒的期限; - 任务取消或超时会关闭 SSH 连接,使会话建立、上传及远端命令退出等待。 - 关闭 SSH 不能证明远端进程已经停止,恢复仍按至少一次交付处理。 -- 发布成功后,只有拥有相同领取标记和版本的线程才能删除待办。 - 新版本、过期线程的迟到结果和确认写入失败都不会导致待办被误删。 -- 节点删除会级联清理待办。原触发端点删除或移动后,会重新选取当前节点的端点; - 暂无端点时保留任务重试。 +- **SSH 连接失败**:检查节点地址、端口、凭据、提权配置及网络可达性。 +- **配置校验失败**:按错误修正协议字段、端口冲突或内核能力,重新保存并发布。 +- **激活或健康检查失败**:查看节点操作记录,确认回滚结果和实际运行状态。 +- **节点离线**:面板保留待办并重试;远端可能仍使用原来的配置。 -这是至少一次交付:节点已经应用配置、数据库确认却未完成时,恢复后可能再次应用配置。 -现有发布过程会生成当前配置并使用原有校验、原子切换及失败回滚,不能把队列恢复 -解释为 SSH 操作恰好执行一次。手工发布仍走原有同步流程。 +自动发布失败不会直接丢弃任务,面板重启后会继续处理。多次修改同一节点时,发布以当前已保存配置为准。任务列表清空不替代节点健康检查。 -## 查看待办 +如果节点已应用配置但面板尚未收到完成确认,重试可能再次发布。排障时结合发布记录、节点操作结果和真实连接情况判断。 -已有发布尝试的结果仍记录在协议发布历史中。待领取或重试状态可用只读查询检查: +## 接下来 -```sql -SELECT node_id, generation, attempts, next_attempt_at, lease_until, last_error -FROM node_config_publishes -ORDER BY next_attempt_at, node_id; -``` - -表中时间使用 UTC。队列表清空表示当前没有自动发布待办;不替代节点在线状态检查。 - -## 验证边界 - -SQLite 文件回归覆盖关闭后重开、租约过期、过期确认、执行期间新请求、 -业务事务回滚、执行失败及数据库确认失败;队列状态测试替换外部执行函数。 - -可选 MySQL 测试覆盖基线建表、旧库补表、独立连接池并发入队与领取、代次合并、 -租约恢复、迟到确认、退避、回滚和节点删除。订单测试覆盖重复确认、发布写入失败 -回滚、读取触发撤权及失败回滚、不同用户并发确认时的套餐容量。运行方法见下节; -未运行真实 MySQL 测试时,不能用 SQLite 结果代替。 - -真实本地 TCP/SSH 故障服务器覆盖握手、会话建立、命令卡住及期限到达,验证生产发布执行器 -退出等待并保存重试。它不运行 Zero 或 systemd,不替代实际节点应用配置、撤权时延或长稳验证。 - -## 重跑 MySQL 验证 - -使用可创建和删除数据库的独立测试账户。测试只迁移和删除自己创建的随机 -`zboard_test_*` 数据库;忽略 DSN 中的库名,不访问已有业务库。 -未设置环境变量时,这组测试明确跳过。 - -```sh -cd backend -export ZBOARD_TEST_MYSQL_DSN='test_user:test_password@tcp(127.0.0.1:3306)/' -go test ./internal/handler -run '^TestMySQL' -count=1 -go test -race ./internal/handler -run 'Test(MySQL|PublishCancellation)' -count=1 -``` +- [节点管理](../guides/node-management) +- [协议服务](../guides/protocol-services) +- [故障排查](../guides/troubleshooting) diff --git a/docs/projects/zboard/reference/node-kernel-lifecycle.md b/docs/projects/zboard/reference/node-kernel-lifecycle.md deleted file mode 100644 index 2959d0c..0000000 --- a/docs/projects/zboard/reference/node-kernel-lifecycle.md +++ /dev/null @@ -1,66 +0,0 @@ -# Zero 节点生命周期规划 - -## 结论 - -浏览器 SSH 终端解决的是人工运维入口,协议配置保存解决的是业务期望状态;两者都不能替代 Zero 内核生命周期管理。zboard 需要把节点自动化明确拆成探测、安装、配置、启动、健康确认和回滚,并把每个阶段的真实结果反馈给管理员。 - -协议保存会触发节点级完整配置发布,不再把单个端点 JSON 写成“暂存成功”。只有 Zero 自身的 `validate`、generation 原子切换、本地 control socket 和新鲜的已认证 Connector 事件全部通过,协议页面才显示配置已生效。 - -## 状态边界 - -节点页面分别展示以下状态,不合并成一个“在线”: - -1. SSH:未配置、待验证、已验证、主机身份变化。 -2. 内核安装:未探测、未安装、安装中、已安装、升级中、失败。 -3. 配置:未生成、待应用、校验中、已应用、回滚、失败。 -4. 进程:未知、启动中、运行、停止、异常。 -5. Zero Connector:按最近一次已认证事件独立判断近期活跃或离线。 -6. 计量:上报凭证状态和最近可信上报时间。 - -## 数据与任务模型 - -新增一对一的 `node_kernel_states`,保存期望版本、已安装版本、二进制 SHA-256、期望/已应用配置修订、当前阶段、服务管理器、最后健康时间和脱敏错误摘要。 - -新增只追加的 `node_operations`,记录 `detect`、`install`、`configure`、`repair`、`upgrade` 操作。每次操作保存请求人、状态、阶段、锁定版本/制品、开始/结束时间和结果摘要。每个节点只允许一个内核操作运行;通用批量任务可以调度多个节点操作,但不直接执行 SSH 脚本。可恢复的客户端幂等键仍属于后续能力。 - -凭证明文不进入操作记录。zboard 使用站点凭证密钥加密保存 Connector 凭证,并只向管理界面暴露前缀;生成的 Zero 配置权限为 `0600`,只把凭证放入 Webhook sink 的 opaque authorization header,不写入操作记录、审计详情或状态输出。 - -## 安装与升级流程 - -1. **预检**:通过已验证 SSH 探测操作系统、架构、libc、systemd、系统提权能力、现有 Zero 版本和服务状态。节点可以直接以 root 登录,也可以为普通登录用户显式配置免密/密码 `sudo` 或带独立 root 密码的 `su`;Linux x86_64 + systemd 节点按 libc 选择制品,禁止为了安装内核而升级系统 libc。 -2. **锁定制品**:`legacy` 仅在无人值守批量任务中默认选择 `zerodenet/zero` 的最新稳定 Release;单节点操作允许管理员显式选择任意已发布的稳定版或预发布版。glibc ≥ 2.34 使用该标签的 `zero-linux-x86_64.tar.gz`;旧 glibc 优先使用同一 Release 的 `zero-linux-x86_64-musl.tar.gz`,并兼容历史 Release 已发布的 `zero-v-linux-x86_64-musl.tar.gz`。每个压缩包都必须存在引用其精确文件名的同名 `.sha256`。前端只提交版本,后端重新按标签解析发布和固定下载地址,不接受任意 URL。GitHub Release 没有可用 musl 制品时,才回退到 `ZBOARD_ZERO_ARTIFACT_DIR` 中同标签的历史版本化制品。`native-local` 则要求显式 `ZBOARD_ZERO_LOCAL_VERSION`,只读取受信任目录内精确匹配的 `zero-v-linux-x86_64-musl.tar.gz` 和 `.sha256`,不访问或替换为 GitHub Release。所有制品都锁定大小和 SHA-256,不接受跨版本替代或未锁定下载。 -3. **暂存与校验**:下载到节点临时目录,核对大小和 SHA-256,执行 `zero version` / `zero build_info`,不覆盖当前版本。 -4. **生成完整配置**:把通用 Webhook Connector、磁盘 outbox、控制 socket和全部启用协议端点及原生 managed users 编译为一个规范化 Zero 配置。配置写入版本化 generation 目录并以 `0600` 权限安装。 -5. **离线校验**:先运行 `zero validate `。校验失败时不修改二进制、配置软链接或服务。 -6. **原子激活**:备份当前二进制和 generation,原子替换二进制及 `current` 配置软链接,安装或更新 `zero.service`,随后 `daemon-reload`、enable、restart。 -7. **分层验收**:内核操作依次确认 systemd active、本地 control socket 的 `zero status --json`、配置摘要和激活开始后的新鲜 `stats.sampled` 等已认证 Connector 事件。Connector 活跃仍作为独立状态展示,不与 SSH 或本地进程状态混合,但首次安装/切换只有通过三段验收才算成功。 -8. **自动回滚**:任一验收失败,恢复上一二进制和配置 generation,重启并再次健康检查;回滚结果也必须落入操作记录和审计日志。 - -## 配置发布 - -协议保存先提交数据库期望状态,随后立即排队发布。zboard 对该节点的全部启用端点和有效订阅凭证生成新的完整配置修订,而不是逐个文件覆盖运行态。新配置先离线校验,再切换 generation 并受控重启;本地健康或 Connector 事件确认失败会恢复上一 generation。协议页的手动操作仅用于重试同一发布链。 - -安装、配置应用和升级共用同一节点操作锁。这样可以避免在升级二进制时同时发布协议配置,也能让重复请求通过幂等键安全返回同一操作。 - -## 分阶段交付 - -- 第一阶段:节点探测、内核状态模型、操作记录和只读 UI,不改变服务器。 -- 第二阶段:固定版本首次安装、完整配置生成、systemd 启动、健康验证和自动回滚。 -- 第三阶段:配置 generation + validate + 受控重启,把协议 SSH 暂存替换为真实生效流程。(已完成) -- 第四阶段:可控升级/降级、批量调度、灰度和失败节点隔离。 - -协议页面必须以 desired/applied 哈希、部署结果和节点健康事实展示状态,不得把文件上传显示成“协议已生效”。 - -## 当前实现(2026-07-26) - -已落地 `node_kernel_states`、`node_operations`、节点检测、当前线上稳定版解析、按 libc 选择 official GNU/面板托管 musl 制品、发布包与二进制双重 SHA-256 校验、节点级完整配置生成、`zero validate`、systemd 原子切换、本地 control socket 与 Connector 事件验收和失败回滚。节点页面可以直接检测并执行“安装 / 升级 / 修复 / 配置同步”,同时展示最近操作的真实阶段与错误。 - -升级判定使用已安装 build ID、实际二进制 SHA-256、期望配置 SHA-256 和本地健康状态:未安装执行安装;版本较旧执行升级;同版本摘要不同执行修复;配置摘要不同执行配置同步;服务或 control socket 异常执行修复。管理员可从稳定发布列表选择精确版本;目标低于已安装版本时,界面必须显示降级语义并二次确认,后端还要求 `allow_downgrade` 与明确版本同时出现。无论选择最新还是历史稳定版,后端都必须重新解析为明确标签、不可变制品 URL 和 SHA-256,随后才允许执行。 - -当前 musl 制品契约为 `zero-linux-x86_64-musl.tar.gz`,同一 Release 必须包含 `zero-linux-x86_64-musl.tar.gz.sha256`,校验文件内部也必须引用这个精确文件名。为确保已发布版本仍可由管理员指定安装,解析器也接受同一 Release 中历史命名的 `zero-v-linux-x86_64-musl.tar.gz` 及其同名校验文件。旧 glibc 节点不会升级系统 libc;新发布不再依赖历史命名。 - -节点 SSH 设置已经把登录认证与系统提权拆开:登录仍支持密码/私钥和固定主机指纹;系统命令根据节点配置使用直接 root、`sudo` 或 `su`。提权密码使用站点凭证密钥独立加密,只通过 SSH stdin 提供,不进入远程命令、任务输出和审计详情;普通交互终端仍保持登录用户身份,由管理员自行决定是否在终端内提权。 - -协议页面保存后的自动 generation 已完成。Zero `0.0.15-rc.3` 起的原生 managed-user 配置为 VLESS、VMess、Shadowsocks、Trojan 和 Hysteria2 携带稳定 `principal_key`;`0.0.15-rc.4` 又为 Mieru 增加 matched-user `principal_key` 归属。面板按目标或节点实际安装版本判断 Mieru:旧节点拒绝创建、重新启用和发布,但保留停用/删除恢复路径;rc.4 及以后版本自动生成每订阅凭据,并在两阶段 validate、激活、健康检查和 Connector 确认后设置 `mieru_principal_ready`。`native-local-mieru` 仅作为兼容名称保留,普通 `native-local` 的 rc.4+ 制品会自动启用同一能力。Connector wire contract 同样跟随目标或节点版本:`0.0.15-rc.1` 及更早版本使用历史 `api_key_env` 与 `push`,`0.0.15-rc.2` 及以后版本使用完整 URL、opaque authorization header 和磁盘 outbox。内核协调使用已解析的目标版本;普通配置发布先探测节点实际版本,避免选择 prerelease 后仍生成旧字段。发布仍使用 `zero validate`、原子软链接、受控重启、control socket、Connector 事件确认和失败回滚。订阅开通、续费、额度调整、额度耗尽与 Connector 活动发现的到期变更都会触发同一发布链。 - -仍未完成的是可恢复的远程幂等键、批量/灰度调度和通过 `config.apply` 热更新替代受控重启。Zero 的策略计数按单进程 principal 执行,因此 zboard 只在订阅恰好有一个活跃且可归属凭证时下发本地限速和设备数;多节点/多凭证全局限速、设备数和剩余额度仍由面板统一计算,不能把完整额度复制给每个内核。zboard 订阅 `stats.sampled` 作为 Connector 活性信号并更新节点摘要,但它不替代 control socket 的进程健康判断。Shadowsocks 继续使用每凭证独立端口以保持现有订阅地址兼容,但运行态归因已经使用原生 `principal_key`。Mieru 的 rc.4 契约目前提供身份归属;未由内核声明的 managed-policy 字段不会由面板臆造。面板稳定 `credential_id` 只保存在数据库/清单中,不进入 Zero 运行配置。 diff --git a/docs/projects/zboard/reference/plugin-marketplace-design.md b/docs/projects/zboard/reference/plugin-marketplace-design.md deleted file mode 100644 index b82191a..0000000 --- a/docs/projects/zboard/reference/plugin-marketplace-design.md +++ /dev/null @@ -1,7 +0,0 @@ -# ZeroDeNet 共享插件市场设计 - -共享设计已迁入 [zerodenet/plugins 的市场草案](https://github.com/zerodenet/plugins/blob/main/docs/marketplace-design.md),后续统一在共享仓库维护。 - -OAuth 插件源码独立维护于 [higanbana986/zboard-oauth](https://github.com/higanbana986/zboard-oauth)。共享市场主分支分别维护 `catalogs/zboard.json` 与 `catalogs/znet-sink.json`,收录各插件仓库发布的发行元数据。开发、使用和发布规范见各仓库 README。 - -共享仓库与独立插件仓库已建立,市场自动化通过审核 PR 同步发行元数据;正式签名安装目录与客户端插件运行时尚未发布。当前 ZBoard 继续使用本仓库描述的 v1 目录及宿主生命周期实现,不因源码迁移改变安装协议。 diff --git a/docs/projects/zboard/reference/plugin-system-design.md b/docs/projects/zboard/reference/plugin-system-design.md deleted file mode 100644 index 5c4dd8b..0000000 --- a/docs/projects/zboard/reference/plugin-system-design.md +++ /dev/null @@ -1,95 +0,0 @@ -# ZBoard 动态插件系统 - -状态:`feature/plugin` 实现 A 段——签名包、插件市场、管理、离线导入、前后台页面、配置运行时及专用身份提供方登录。当前还提供宿主管理的包准入、加密 JSON 私有存储和声明式配置/数据迁移,见 [宿主生命周期与数据](/projects/zboard/plugins/governance)。支付、凭证轮换、事件订阅、任务与关系表扩展属于后续能力,当前安装器拒绝声明这些能力的包。使用方法和准确的包格式见 [插件开发与运维](/projects/zboard/plugins/development)。 - -## 核心所有权 - -ZBoard 的核心定位是基础面板。在线支付及其他超出基础管理范围的能力通过插件实现;扩展需求通过明确的宿主接口接入。 - -核心独占用户、凭证、订单、权益、流量和节点配置发布。插件负责扩展交互及外围集成,通过宿主明确开放、版本化的能力提出请求。插件 SDK 不提供数据库连接、GORM、任意 SQL、任意核心命令、管理员令牌、节点控制地址或节点凭证。 - -`surface` 表示页面所在位置,不授予权限;声明后台页面不意味着插件能访问后台业务。页面位置不授予权限;有效能力取当前包声明、宿主准入、调用身份和核心策略的交集。插件生命周期与核心事务相互独立:停用或卸载插件不撤销已经提交的核心工作,不改变用户、订单、订阅或节点状态。 - -当前 RPC 包含插件身份、健康检查、配置验证、配置应用、已保存配置测试,以及专用身份提供方元数据/身份验证。登录状态、绑定与会话由核心实现,详见 [身份提供方契约](/projects/zboard/plugins/identity-reference)。浏览器桥只有最小页面上下文及管理员配置能力。新增扩展点必须先在核心服务内定义命令、鉴权、资源范围、幂等和结果语义,再增加独立能力协议与验证用例。 - -## 参考 Sub2API 的取舍 - -参考提交 `270eac6973049fe1b50eb75560a74a029e82884c` 的签名包、go-plugin/gRPC、版本要求、配置页面桥及配置应用机制;ZBoard 使用自己的 `.zbplugin`、协议和贡献声明,不兼容 `.s2plugin`。 - -- 使用独立服务进程、gRPC、握手及运行身份核验;纯页面插件无需进程。 -- 包以 Ed25519 签名完整原始 manifest,manifest 用 SHA-256 绑定文件内容。 -- 宿主兼容范围、发布者测试版本、协议版本分别校验;未声明测试的兼容版本启用时需管理员确认。 -- 升级由宿主准备候选数据和进程,在同一事务内切换版本、配置、数据和准入;成功保留原启停状态,失败保留旧实例与数据。保留最多 30 个版本的记录;恢复旧版本需校验数据和已有配置,不自动向下迁移。 -- 配置先验证和应用,再加密提交;持久化失败恢复旧配置,恢复失败终止进程并标记异常。重启以数据库已提交配置为准。 -- 首版一个活动宿主,由数据库租约和 epoch 限制,不宣称多实例协调已经完成。 - -独立进程用于故障隔离,并不是不可信原生代码的 OS 沙箱。签名只证明来源与完整性,不证明代码安全。服务组件必须来自运营者信任并审查的发布者;启动不继承宿主环境、使用独立工作目录和加密 RPC,但当前没有 UID、文件系统、网络或 CPU/RSS 的强制沙箱。运行任意第三方不可信二进制不在本期能力内。 - -## 交付和动态生命周期 - -同一包可包含 `public`(公开前台)、`account`(用户前台)、`admin`(管理后台)入口及可选多平台服务二进制。管理系统展示来源、范围、运行组件、兼容性、当前版本、错误和操作记录。 - -安装路径统一为:市场下载或离线上传 → 包大小/路径检查 → 发布者签名 → manifest 与能力白名单 → 文件摘要 → 私有目录原子保存 → 候选配置/数据迁移与运行时准备 → 安装、准入、数据和迁移记录原子提交。首次安装默认停用;已有配置或数据迁移需要候选原生进程校验时,宿主会启动它,失败则保留旧安装。不兼容包拒绝安装。 - -启用验证完整包及当前平台,启动可选进程、核验身份、应用配置后提交活动状态,随后页面目录可见。停用先关闭活动状态并递增 generation,撤销页面会话,再终止进程;管理器串行化正在执行的配置操作。当前没有业务 RPC,因此没有在途付款或任务可排空。未来业务能力需独立实现 drain 和超时,不能把配置操作串行化当作业务排空。 - -卸载由宿主停止运行并撤销会话,删除所有保留版本的程序/页面,保留安装墓碑、加密配置、私有数据与操作记录。单独删除配置不清理核心事实。重新导入同 ID 必须仍为相同签名发布者。 - -## 市场与离线导入 - -市场按 ZeroDeNet 多宿主共享方向演进,覆盖 ZBoard 与 ZNet Sink;共享分发协议,各宿主分别负责能力与生命周期。仓库命名、目录兼容和分阶段落地见 [共享插件市场草案](/projects/zboard/reference/plugin-marketplace-design)。以下描述为当前已实现的 ZBoard v1 目录能力。 - -市场来自部署配置指定的签名目录,不允许从浏览器提交任意下载地址。目录具备有效期,发布者和目录签名均使用运营者配置的可信公钥;安装重新获取目录并比对用户选择的摘要,然后校验下载包的摘要、签名、ID、版本及发布者。 - -下载仅允许公开 HTTPS 的 443 端口,禁用重定向和环境代理,DNS 解析后检查全部地址并固定连接已检查 IP。未配置市场显示配置提示;离线导入无需网络,使用完全相同的包校验链。首版没有预置或虚构公共市场,也不提供自动更新、评分和开发者上架后台。 - -## UI 边界 - -路由在宿主编译时固定,插件只贡献页面描述;导航从活动页面目录刷新。各 surface 由宿主鉴权。插件 HTML 在 `sandbox="allow-scripts"` 的 iframe 内运行,不授予同源、弹窗、表单、顶层导航能力。 - -宿主签发十分钟资源会话,绑定插件、页面、surface、用途、用户和 generation。资源 token 只读取该插件签名包内 UI 文件,不暴露二进制、manifest、源码映射或其他包。CSP 禁止网络请求、表单和子 frame;不向 iframe 传递宿主登录令牌。HTTP 会话撤销、停用、版本变化、宿主重启均使旧资源失效。 - -postMessage 校验发送窗口、桥令牌、请求 ID、操作白名单和消息大小。管理员配置页面才可调用 config.load/save/test;普通业务页面只能取得 plugin_id/page_id/surface。宿主卸载容器时撤销会话并取消请求,旧 generation 响应不进入新页面。导航和 iframe 会话每 15 秒可见时刷新,停用后的后端访问立即拒绝,已经绘制的页面在下一次检查时移除。 - -## 配置和故障恢复 - -配置为最长 64 KiB 的 JSON 对象,整份使用既有 CredentialCipher 加密;管理 API 返回是否配置、revision 以及可选的插件公开配置投影,不回显秘密值。当前使用 JSON 编辑器或插件自带配置页,不声称已实现 JSON Schema 表单生成。服务插件不能在 ApplyConfig 或 TestConfig 内执行扣款等业务副作用。 - -配置持久化使用 revision CAS,生命周期使用 generation;宿主租约检查以事务中的 epoch 为准。配置应用成功后 DB 提交失败会重新应用原配置;宿主崩溃后所有进程重新从已提交配置恢复。运行中操作记录在重启时标记 interrupted。进程异常只标记对应插件 failed 并撤销其会话,不把未确认业务结果标成成功。 - -插件目录、数据库和凭证加密密钥必须一起备份;密钥变更需复用核心密钥迁移流程。SQL 迁移通过新增 `0002_plugins` 建表,MySQL/SQLite 均有明确脚本,不修改已发布的核心 baseline。卸载某个插件不回滚全局 schema。 - -## 凭证轮换能力的后续接入路径 - -以后需要“插件动态修改用户凭证并通知节点”时,路径固定如下,当前版本尚未开放此能力: - -```mermaid -sequenceDiagram - participant P as 插件 - participant H as 宿主能力网关 - participant C as 核心凭证服务 - participant D as 核心数据库 - participant W as 核心节点发布器 - participant N as Zero节点 - P->>H: RotateCredential(请求ID, 目标资源, 预期版本) - H->>H: 检查能力、调用身份、资源范围和generation - H->>C: 经授权的专用命令 - C->>D: 同事务更新凭证并写node_config_publishes - D-->>C: 提交成功 - C-->>P: operation_id + 已提交 - W->>D: 领取持久化发布工作 - W->>N: 通过现有控制API应用配置 - N-->>W: 应用结果 - W->>D: 保存逐节点结果与重试状态 - P->>H: 查询operation_id状态 -``` - -“数据库已提交”“节点已应用”“旧会话已终止”必须分开表达。节点失败由核心发布器重试,部分节点成功需显示部分完成。轮换是否终止已有连接由核心命令明确决定,不能从配置更新推断。插件停用后核心发布继续执行;插件不能拼装节点配置、直接发节点命令或自行改写发布记录。 - -## 后续独立能力 - -身份提供方已经通过专用契约落地。后续支付能力仍需独立设计:插件负责提供方通信及回调验签,核心拥有订单金额/币种、支付 attempt、幂等确认和权益发放。回调成功 ACK 必须在宿主持久化确认后产生;重复、乱序、结果未知和停用中回调均需要独立验收。 - -事件、定时任务和插件数据 API 后续分别定义。核心事件用事务 Outbox、至少一次投递及幂等,不允许可选插件执行拖住核心事务;任务使用持久化触发标识和租约;插件自有存储由宿主按 plugin_id 隔离,不开放 SQL。灰度、业务 drain、多活动宿主、硬资源限制和不可信代码沙箱都不得由当前健康检查推导为已实现。 - -第三方登录与注册、多提供方快捷配置、自定义 OAuth2 字段映射和配置密钥保留契约见 [插件身份能力](/projects/zboard/plugins/identity-reference)。配置读取可包含插件投影的公开字段;密钥保持隐藏。 diff --git a/zboard-document-migration.json b/zboard-document-migration.json index be47463..a9e9d39 100644 --- a/zboard-document-migration.json +++ b/zboard-document-migration.json @@ -6,132 +6,170 @@ { "source": "docs/README.md", "destination": "docs/projects/zboard/guides/index.md", - "source_sha256": "92a97ca0e0a609b9893d787163bc4b9aeb736f7906cc6e71fa172713e6767288" + "source_sha256": "92a97ca0e0a609b9893d787163bc4b9aeb736f7906cc6e71fa172713e6767288", + "status": "retained_or_rewritten" }, { "source": "docs/getting-started.zh-CN.md", "destination": "docs/projects/zboard/guides/installation.md", - "source_sha256": "3b95936d16d746e4e46ffbdd7657b57f66d37ecc8c7307fba6df5a4540492a1f" + "source_sha256": "3b95936d16d746e4e46ffbdd7657b57f66d37ecc8c7307fba6df5a4540492a1f", + "status": "retained_or_rewritten" }, { "source": "docs/getting-started.md", "destination": "docs/projects/zboard/guides/installation-en.md", - "source_sha256": "cce43ed1c3d9ad71f642248bbbe0f84a5771870290a47e75c63051e2ecb2fd8b" + "source_sha256": "cce43ed1c3d9ad71f642248bbbe0f84a5771870290a47e75c63051e2ecb2fd8b", + "status": "retained_or_rewritten" }, { "source": "docs/core-baseline.md", - "destination": "docs/projects/zboard/reference/core-baseline.md", - "source_sha256": "1290d8a6dc16d2f7c49320c46230027d4b54730c944265b5b4f2d097de2707b6" + "source_sha256": "1290d8a6dc16d2f7c49320c46230027d4b54730c944265b5b4f2d097de2707b6", + "excluded_destination": "docs/projects/zboard/reference/core-baseline.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/data-model.md", - "destination": "docs/projects/zboard/reference/data-model.md", - "source_sha256": "0534d6ee4df981908f73950e006aeea4504617bcd6fc214546b092f3b1b4fda9" + "source_sha256": "0534d6ee4df981908f73950e006aeea4504617bcd6fc214546b092f3b1b4fda9", + "excluded_destination": "docs/projects/zboard/reference/data-model.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/database-migrations.md", - "destination": "docs/projects/zboard/reference/database-migrations.md", - "source_sha256": "4037a83bb4152454c494f983b7df4456b48b8e66c72f97b977162834daa5b82c" + "source_sha256": "4037a83bb4152454c494f983b7df4456b48b8e66c72f97b977162834daa5b82c", + "excluded_destination": "docs/projects/zboard/reference/database-migrations.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/development.md", "destination": "docs/projects/zboard/contributing/development.md", - "source_sha256": "d671964dfa51d87d7b383c705d814d89c336357323f3250daadd84b18009acfc" + "source_sha256": "d671964dfa51d87d7b383c705d814d89c336357323f3250daadd84b18009acfc", + "status": "retained_or_rewritten" }, { "source": "docs/managed-rule-compatibility.md", "destination": "docs/projects/zboard/reference/managed-rule-compatibility.md", - "source_sha256": "16d32d883111c1e05eeafb1149552efeb1e2022ef8644e83377973e8625901df" + "source_sha256": "16d32d883111c1e05eeafb1149552efeb1e2022ef8644e83377973e8625901df", + "status": "retained_or_rewritten" }, { "source": "docs/mieru-kernel-contract.md", - "destination": "docs/projects/zboard/reference/mieru-kernel-contract.md", - "source_sha256": "24583bf35106e05b6b070f2d5205f827cc272ceab74a79cfca3944774b7e9a85" + "source_sha256": "24583bf35106e05b6b070f2d5205f827cc272ceab74a79cfca3944774b7e9a85", + "excluded_destination": "docs/projects/zboard/reference/mieru-kernel-contract.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/network-fronting.md", "destination": "docs/projects/zboard/guides/network-fronting.md", - "source_sha256": "b5d15a14318ec076f4c437a338bb613b8cd5c3695644c9d097029a5f92d80691" + "source_sha256": "b5d15a14318ec076f4c437a338bb613b8cd5c3695644c9d097029a5f92d80691", + "status": "retained_or_rewritten" }, { "source": "docs/node-cleanup.md", "destination": "docs/projects/zboard/guides/node-cleanup.md", - "source_sha256": "e2599ecb3b01f2f2bcaf5ca451ee1167daa9c43ad5c1c52ddf78ba9d1555af0f" + "source_sha256": "e2599ecb3b01f2f2bcaf5ca451ee1167daa9c43ad5c1c52ddf78ba9d1555af0f", + "status": "retained_or_rewritten" }, { "source": "docs/node-config-delivery.md", "destination": "docs/projects/zboard/reference/node-config-delivery.md", - "source_sha256": "ab17515b729b7dce00bc9d3c7eb94797d9489d701117301411225315f01b93ec" + "source_sha256": "ab17515b729b7dce00bc9d3c7eb94797d9489d701117301411225315f01b93ec", + "status": "retained_or_rewritten" }, { "source": "docs/node-kernel-lifecycle.md", - "destination": "docs/projects/zboard/reference/node-kernel-lifecycle.md", - "source_sha256": "060878515c8552182917d644f522f39673ebdb25ef3657c5b9b795c4be99af20" + "source_sha256": "060878515c8552182917d644f522f39673ebdb25ef3657c5b9b795c4be99af20", + "excluded_destination": "docs/projects/zboard/reference/node-kernel-lifecycle.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/plugin-governance.md", "destination": "docs/projects/zboard/plugins/governance.md", - "source_sha256": "1bf5ac826f530767c43e74cfdf95d0d8242b1f48358c18f0c6e027e9ca42e7e5" + "source_sha256": "1bf5ac826f530767c43e74cfdf95d0d8242b1f48358c18f0c6e027e9ca42e7e5", + "status": "retained_or_rewritten" }, { "source": "docs/plugin-identity.md", "destination": "docs/projects/zboard/plugins/identity-reference.md", - "source_sha256": "a08c051771cff5328167c462099b49f6fe1f4c15043046930f1b96b75bd81e58" + "source_sha256": "a08c051771cff5328167c462099b49f6fe1f4c15043046930f1b96b75bd81e58", + "status": "retained_or_rewritten" }, { "source": "docs/plugin-installation-trust.md", "destination": "docs/projects/zboard/plugins/trust-en.md", - "source_sha256": "9f3f42f7291ce69c15fbed439f7f6a72ffa3f27b1f7e795fa8d460062198e9bf" + "source_sha256": "9f3f42f7291ce69c15fbed439f7f6a72ffa3f27b1f7e795fa8d460062198e9bf", + "status": "retained_or_rewritten" }, { "source": "docs/plugin-installation-trust.zh-CN.md", "destination": "docs/projects/zboard/plugins/trust.md", - "source_sha256": "63716eaff9ff3e1cc447b66da5cca526cf2eef48792f61f6804f8b8431305382" + "source_sha256": "63716eaff9ff3e1cc447b66da5cca526cf2eef48792f61f6804f8b8431305382", + "status": "retained_or_rewritten" }, { "source": "docs/plugin-marketplace-design.md", - "destination": "docs/projects/zboard/reference/plugin-marketplace-design.md", - "source_sha256": "de953f3347a362412ce345dc5a534fbeafb2d62c8c59b6f54c6c130277f9d3a0" + "source_sha256": "de953f3347a362412ce345dc5a534fbeafb2d62c8c59b6f54c6c130277f9d3a0", + "excluded_destination": "docs/projects/zboard/reference/plugin-marketplace-design.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/plugin-system-design.md", - "destination": "docs/projects/zboard/reference/plugin-system-design.md", - "source_sha256": "cbeb5624d82280bc09b2e1aa5c153ffa90d6c95671840b85de24058f64dd6969" + "source_sha256": "cbeb5624d82280bc09b2e1aa5c153ffa90d6c95671840b85de24058f64dd6969", + "excluded_destination": "docs/projects/zboard/reference/plugin-system-design.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/plugins.md", "destination": "docs/projects/zboard/plugins/development.md", - "source_sha256": "50c5ee0b0d9413a9a8fcfed2f84474ad5ec20cb4099478d01835628af7cdd5a3" + "source_sha256": "50c5ee0b0d9413a9a8fcfed2f84474ad5ec20cb4099478d01835628af7cdd5a3", + "status": "retained_or_rewritten" }, { "source": "docs/public-subscription-filtering.md", "destination": "docs/projects/zboard/guides/subscription-filtering.md", - "source_sha256": "49ac8e1c5683b402f5955ad8fe49061393e6e6664ed5b3ce5101085a579017d1" + "source_sha256": "49ac8e1c5683b402f5955ad8fe49061393e6e6664ed5b3ce5101085a579017d1", + "status": "retained_or_rewritten" }, { "source": "docs/release/2026-09-06-core-rc.md", - "destination": "docs/projects/zboard/reference/history/core-rc.md", - "source_sha256": "7e9166cf98846bb98c1047c547e9886e54e70b99b73577f20ed023659d1d1975" + "source_sha256": "7e9166cf98846bb98c1047c547e9886e54e70b99b73577f20ed023659d1d1975", + "excluded_destination": "docs/projects/zboard/reference/history/core-rc.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/release/v0.0.1.md", - "destination": "docs/projects/zboard/reference/history/v0.0.1.md", - "source_sha256": "ff65e5c0db7f5f0d61129b3cf2fb23200d46fa6139feb7e2ff45e9aa4946fe6c" + "source_sha256": "ff65e5c0db7f5f0d61129b3cf2fb23200d46fa6139feb7e2ff45e9aa4946fe6c", + "excluded_destination": "docs/projects/zboard/reference/history/v0.0.1.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/release/v0.1.0-launch-checklist.md", - "destination": "docs/projects/zboard/reference/history/launch-checklist.md", - "source_sha256": "642ba473b2da6855b87ca5d6862f312e590d8abd4ed764d3065d5b011bdd1e69" + "source_sha256": "642ba473b2da6855b87ca5d6862f312e590d8abd4ed764d3065d5b011bdd1e69", + "excluded_destination": "docs/projects/zboard/reference/history/launch-checklist.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "docs/roadmap.md", - "destination": "docs/projects/zboard/reference/history/roadmap.md", - "source_sha256": "8def6fc6c8c53489de86b755e284adf2cbdfbf9dbf0c19d76a6a60ba3c805221" + "source_sha256": "8def6fc6c8c53489de86b755e284adf2cbdfbf9dbf0c19d76a6a60ba3c805221", + "excluded_destination": "docs/projects/zboard/reference/history/roadmap.md", + "status": "excluded", + "reason": "Development history or superseded implementation snapshot; removed from the public site." }, { "source": "deploy/docker/README.md", "destination": "docs/projects/zboard/guides/storage-and-backups.md", - "source_sha256": "11e7b29c7852c0e0bba912b53beecacfa4921344e7d3eb772933650a3145b75c" + "source_sha256": "11e7b29c7852c0e0bba912b53beecacfa4921344e7d3eb772933650a3145b75c", + "status": "retained_or_rewritten" } - ] + ], + "publication_policy": "Publish current usage and plugin integration guides; exclude development plans, temporary contracts and historical acceptance records." }