Files
dsh_shenxian/dsh-server-docs/BRIEF.md
T
admin 971ccc3703 feat(auth): 注册页人机验证 + 邮箱验证码;品牌标识去 DeepSeek(附域名迁移线 序㊿ 补提交)
三条线合并入库 —— 均已完成并上线(源码与生产一致,此前只部署未入仓)。
⚠️ 其中域名迁移线为**另一会话**产出,本会话只做入库、**未复验其正确性**(它自报零回归)。

【档案 134 · 注册页人机验证 + 邮箱验证码】
- DB 迁移 v10:users.email(唯一索引 LOWER(email))+ email_codes 事件表(2 索引)
- 新增模块 src/web/{register-guard,mail,turnstile,email-code}.ts
- routes/auth.ts:新增 GET /api/auth/register/config、POST /api/auth/register/email-code;
  注册接口加人机验证与验证码校验;config.ts 新增 12 项配置(默认空 ⇒ 不配 = 老行为)
- 邮件走**可插拔驱动**(brevo/http/log),发件人 [email protected](Brevo 域名已认证 + DKIM + SPF)
- 防爆破:三层配额(邮箱 6/h、8/天;IP 20/h;全局 200/h)+ 递增冷却阶梯
  (60→60→180→300→900→1800s)+ 试错 5 次作废 + 码只存哈希 + 单次使用 + 与用户名绑定
- Turnstile 服务端校 **success + action + hostname 三项**:sitekey 是公开的,
  只校 success 时"拿我们的 sitekey 在自己站点替真人取合法 token 再打我们接口"这条路是通的
- 新增 test/register-guard.test.mjs(19 用例)

【档案 137 · 品牌标识改造 — 去 DeepSeek 图形】
- login/register/admin 页头:删 DeepSeek 鲸鱼图标 + 「DeepSeek」文字图形
  → 平台标识(中文「能力枢纽」/英语及其他语言「CapabilityNet」,走 i18n 词条 brand.name)
- portal 顶栏换图标(页面名「管理门户」保留)
- 新建 web/favicon.svg(平台自有 hub 图标,避开 DeepSeek 蓝)+ 四页 favicon 指向它
- 新增 test/i18n-brand.test.mjs(node:vm 跑真实 i18n.js,六条语言路径断言渲染结果)
- scripts/verify-static.mjs 新增 SVG 段:XML 注释不得含 ASCII 双连字符(否则整份 SVG
  解析失败、图标静默不显示 —— 实际踩到过)
- 🔴 会话页面(实例内官方 dsh 界面)的标识**按用户要求未动**(也受 R2 约束)

【档案 135/136 · 域名迁移线(另一会话产出)】
- 域名收敛为 ai1net.com;旧域 alotbuy.com 降级为 301 过渡装置
- src/net/relay/{addr-override,directory,rendezvous,switcher}.ts 种子与候选链更新;
  src/web/server.ts、src/worker/relay-tunnel.ts、scripts/verify-cluster-domain.mjs
- 档案 136 = 控制面按两台中继取并集(**已立项、未落地**)

验证(本会话两条线):新增单测 21 条全通过|全量 221 pass / 0 fail / 1 skipped|
verify-static 全合格|其余 10 个 verify 脚本全 OK|线上实测:Turnstile 假 token 403、
发码 delivered、四页 deepseek 命中 0、favicon 200。
2026-09-19 09:11:24 +08:00

80 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BRIEF — 现状卡(**AI / 人 首读这一份**)
> **用途**:30 秒掌握「现在是什么样、正在做什么、该读哪一篇」。只写**结论与指针**,细节的单一来源见每行括注。
> **防漂移**:本文件是**人工维护的摘要层**,不复制细节;`scripts/docs-audit.py` 会检查本文件引用的档案号是否存在、域名/阈值等关键串是否与来源文件一致。
> **最后人工核对**:2026-09-19 06:4x
---
## 1. 一句话
多租户 DSH 托管平台:门户(`ai1net.com`)+ 每用户一个独立 dsh 实例(bwrap 合成根 + 独立 uid + systemd scope)。
**自 2026-09-15 起为集群形态**:`47.77.182.89` = **Manager**(cluster 模式,兼本地 Worker `w-47`)|**106 = Worker `w-106`**(经 SSH 反向隧道)。
## 2. 现行事实(结论层 · 改任何东西前先对齐这里)
| 项 | 现行值 | 单一来源 |
|---|---|---|
| **入口** | 门户 `https://ai1net.com`;用户实例 `https://<用户名>.ai1net.com`;旧域 `alotbuy.com` 自 **2026-09-19** 起**降为 301 过渡装置**(门户块 `return 301 https://ai1net.com$request_uri`;**仅** `relay-direct.alotbuy.com` 与旧域 `/dshs-relay`、`/dshs-overlay/bootstrap` 继续透传 = 覆盖网络兜底);**relay 候选链同步由 5 条压到 3 条**(删掉两条「摘名不同、物理同落 47 同一路径」的伪多样性,⛔ 未减少真实冗余)。⛔ **退役条件 = 旧域 30 天访问量为 0** 后再删 `relay-direct.conf` 与 `dsh.alotbuy.com.conf` | 档案 22 / **135** / `DEPLOY §1` / `ops/域名迁移_ai1net_20260919/RUNBOOK-cutover.md §5` |
| **服务** | systemd `dshs`(`127.0.0.1:3080`)+ 宝塔 nginx 反代(CF 回源 443) | `DEPLOY §1` |
| **集群拓扑** | 47 = **Manager**(`deployMode=cluster`;控制面库 = 47 上 **PG13** `/var/lib/dshs-pg`,单元 `dshs-pg`,`127.0.0.1:15432`)+ 本地 Worker `w-47`(19100)|**106 = Worker `w-106`**(19000,**经 SSH 反向隧道**落在 Manager loopback,`DSHS_TUNNEL_TARGET`)|存量用户锚 `w-47`、新用户按容量落 `w-106`(**粘性优先**,`epoch` fencing 防双写)。⛔ 47 兼作 Worker 是**有意设计**,勿当待修项。**回滚** = `rm -f /etc/systemd/system/dshs.service.d/cluster.conf && systemctl daemon-reload && systemctl restart dshs` | `交接单/T08 §10` / `集群化改造方案_Manager-Worker_20260914.md` |
| **运行时** | dsh **0.1.5-rc.1**(2026-09-14 由 0.1.2-rc.1 升级,走档案 07 五阶段全流程;官方包**零改动**)| Node 22.23.2 | pnpm 9.15.9 | nginx 1.28.3 | ⚠️ **bwrap 逐机不同:47 = 0.4.0 / 106 = 0.11.0**(`--perms` 属 0.5+ ⇒ 47 上 `Unknown option` ⇒ 沙箱起不来 = 所有实例全挂;要权限**用 `--tmpfs`**) | `DEPLOY §4` | 升级档案 `04/90` | `交接单/T08 §10` |
| **隔离** | `ISOLATION_MODE=account`;每用户 uid + bwrap 合成根(`/usr /lib64 /etc` 只读 + 私有 `/tmp` + `--unshare-pid`)+ scope(**内存 = 基础 448 MiB、最多浮动到 1024 MiB**(cgroup `MemoryHigh=MIN` 软限 + `MemoryMax=MAX` 硬限;**与插件开关无关**,2026-09-14,档案 **96**);CPU 150% / TasksMax 128;**V8 堆另须 `--max-old-space-size=256`**);**loopback `127.0.0.0/8` 已封** | 档案 16 / 39 / **58** / 94 / **96** |
| **实例页右下角** | **📁 我的文件**(浏览工作区 + 下载 AI 产出)| **🧭 能力**(权威能力清单)| 老会话档位过时会有**顶部提示条** | 档案 56 |
| **回到实例页面** | 页面可见即**自检**:顶部提示条「正在检查工作区连接…」→ 若判定页面与实例**已脱节**(探针 2.5 s 无 200)则亮**覆盖层**并**就地恢复**(`enter` 带新 token 原地跳回、**保留路径**),**不跳门户域、无需手动刷新**;导航路径(刷新/首次进入)仍走 `wake.html` 过渡页 | 档案 77(承 72) |
| **插件导入 / 上传** | 即做**兼容性预检**(semver 依赖范围 + 运行时导出符号比对),不兼容当场拒收,不再等实例崩 | 档案 71 |
| **普通用户可见** | 实例内:**功能插件** section、目录选择器(根 = 自有 `ws`);技能 API `/api/skills/mine` | 档案 36 / 41 |
| **admin 管理面** | 门户:服务 / **密钥** / 用户 / 技能 / 插件管理 + 运行环境;会话内 `portal-entry` 卡片**一键整页跳门户** | `portal.html` / 档案 47 |
| **清理阈值** | `ws` ≥ **2048 MB** → 清 T1 平台产物 + T2 超 **90 天**顶层脚本;`sessions` ≥ **1024 MB** → 清超 **365 天**;回收站 **30 天** | 档案 28 / `02 §C.7` |
| **定时任务** | 每小时 :05 用量快照 → 04:10 工作区清理 → 04:20 会话回收 → 04:40 回收站清空 → **每周日 05:00 全量备份** | `DEPLOY §6.5` |
| **证书** | `ai1net.com + *.ai1net.com`(2026-09-19 经 **DNS-01** 签发,凭据 `/etc/cloudflare-ai1net.ini`,已入 certbot 自动续期)|`alotbuy.com + *.alotbuy.com`(旧域,**仅过渡期保留**)|**必须 `--dns-cloudflare-propagation-seconds 60`** | 档案 22 / `02 §C.1` / RUNBOOK §5 |
| **红线** | 不自动升级 dsh;不改官方 dsh 主程序与缓存;client bundle 禁 `exports.default`;服务器 docs 保持 root 600;未明确要求不 commit/push;⛔ **禁止人工删锁 / 接管**(**R9**) | `README §红线` |
## 3. 当前待办(**单一来源 = `03-路线图与待办.md`** + **已规划的单子见 `交接单/README.md §一`**)
> `T01–T08` **全部完成归档**;在途单 = **无**。以下只列最相关的几条。
| 优先级 | 事项 | 备注 |
|---|---|---|
| 🔴 **第一件实事** | **会合 / 中继从 Manager 拆成可独立部署的组件** | 现状 = 绑在 Manager 上的**单中心 SSH 反向隧道**;是所有后续(多区域 / 多中心 / 骨干层)的**前置**。**只读取证 + 改造方案已产出**(工作区根 `会合中继拆分_取证与改造方案_20260916.md`,S0–S4 分步 + 每步验收/回滚)⇒ 下一步 = 从 **S0(抽接口,零行为变更)** 开工 |
| 🟡 待排期 | **T08 收尾项**:`join-worker.sh` 一键装机 | 集中日志 / metrics | `smoke-domain` 定性 | drop-in 里 PG 口令收权(现 root 可读)| 106 上的**旧控制面单元**待清理 | `03-路线图 §二` 🟡 / `交接单/T08 §16.5` |
| 🟡 待排期 | **106 的 provisioner 未铺** ⇒ 新用户落到 106 后**无人建号**(uid 须由 Manager 下发;47 上那套读 SQLite 的脚本在集群下失效) | 工作区根 `跨节点迁移与节点自举_完整流程方案_20260916.md` |
| 🟡 待排期 | 覆盖网络线后续:**`MEMORY.md` 精简**(已超体量上限、每轮都被注入)| 之后按**档案 112「只做三件事」**(presence + 游戏服放 L1 + 块级内容寻址)开工 | `03-路线图 §二` |
| ⏳ **待拍板** | **骨干节点的服务范围** = A 只服务自己名下设备 / B 服务全网(**倾向 A→B 渐进**) | 档案 **105 §七** |
| ⏳ 待拍板 | **D6**(集群化最后一问,**不阻塞**) | `集群化改造方案_Manager-Worker_20260914.md` |
| ❓ 待复核 | **档案 65**(功能插件启停 ↔ web provider 托管段联动)是否已随 09-13~09-15 各轮上线 —— 本节原行停在 09-12「等窗口」,未确认 | 档案 65 §7.3 |
## 4. 最近动作(详见 `03-路线图 §已完成`)
**09-16** 覆盖网络 / 客户端化线:**10 份规划转正式档案 103–112**(`4e3a1a4`)+ **会合/中继拆分的只读取证与改造方案**产出(工作区根 `会合中继拆分_取证与改造方案_20260916.md`;**零代码、零服务器改动**)|`guest` 用户迁至 `w-106`(epoch 4)|106 补齐实例运行能力(**`/var/lib/dshs/users` 权限 711** —— 原 `drwx------` 会致实例必崩)+ ffmpeg/ffprobe。
**09-15** **T08 集群化 + 生产整体切换**:47 = Manager、106 = Worker,控制面库换成 47 上的 **PG13**;`guest` 迁移;实例内存配额与插件开关**解耦**(档案 96);文档库**并入代码仓**(R4 选 a);开源导出 K8s 残留清零。**此前**:档案 100/101 实例内「我的技能」+ 分区改名 + 页内 tab(`business-plugins` 0.3.22)|档案 102 语言切换搬入「用户设置」(0.3.23 + `portal-entry` 0.5.5)|档案 93 兼容收口|档案 88 内置 dsh 安装路径探测|档案 77 回到页面自检 + 就地恢复|档案 73 让锁真正拦得住人|档案 72 实例回收后自动唤醒重建连接|档案 71 插件兼容性预检|档案 69 并发治理(commit 常态化 + 服务器侧操作锁)。
## 5. 高频问题 → 读哪一篇
| 想做的事 | 读 |
|---|---|
| 理解平台架构 / 为什么这样隔离 | `01-规划与架构` + 档案 16 / 39 |
| 域名、证书、Cloudflare | 档案 22 + `02 §C.1` |
| 实例起不来 / 崩溃循环 / 401 | 档案 20 / 52 / 51 + `02 §C.4` |
| 用户看不到目录 / 工作区选择 | 档案 18 / 34 |
| 功能插件的投放与启停 | 档案 16 / 36 / 37 |
| 技能共享 / 上传 / 启停 | 档案 10 / 11 / 41 |
| 磁盘用量与清理策略 | 档案 28 + `02 §C.7` |
| 备份与恢复 | `02 §C.8` + `DEPLOY` |
| 准备升级 dsh | 档案 26(六类耦合点回归清单) |
| 重建 / 交接部署 | `DEPLOY-本部署.md` |
## 6. AI 读取顺序(4 步,避免读全库 ≈30 万 tokens)
1. **本文件**(BRIEF)→ 2. `INDEX.md` 场景表(定位篇目)→ 3. 目标档案**头部**(日期/状态/结论)→ 4. 需要时再读全文。
- **默认不读**:`archive/`(历史全文)、`scripts/` `ops/`(工具与配置)、`*.bak*`、`04-调整方案/poc/`(源码,按需)。
- **过滤工具**:`python3 scripts/docs-manifest.py` → 产出 `docs-manifest.json`(每份文档的 状态 / 日期 / tier / 被引用次数 / 字符数),可用于**先筛后读**。
- **改文档后**:`python3 scripts/docs-audit.py`(编号冲突 / 悬空引用 / 重复 / 体量;退出码非 0 即需处理)。
## 7. 文档层约定
单一来源:清单与状态 = `INDEX.md` §二|待办 = `03-路线图`|部署事实 = `DEPLOY-本部署.md`|术语以档案 38b 为准|域名以 `ai1net.com` 为准。详见 `README §阅读约定` 与档案 53 / 54。
**归档编号**:至 **112**(其中 103–112 = 覆盖网络 / 客户端化 10 份规划);**编号 63 是空号,勿补占**。
**本机工作区(2026-09-13 起)**:`E:\ProgramData\AI技能\aliyun-dsh-server`(文档库工作树 = `dsh-server-docs/`);代码仓仍为 `D:\github\dsh_shenxian`。历史文档里出现的 `D:\AI技能\...` 一律是**迁移前旧值**,勿照抄执行。