diff --git a/docs/architecture/运维/assets/02-部署链时序.svg b/docs/architecture/运维/assets/02-部署链时序.svg
new file mode 100644
index 00000000..3cbe8899
--- /dev/null
+++ b/docs/architecture/运维/assets/02-部署链时序.svg
@@ -0,0 +1,100 @@
+
diff --git a/docs/architecture/运维/assets/04-冒烟门12项.svg b/docs/architecture/运维/assets/04-冒烟门12项.svg
new file mode 100644
index 00000000..4b3371ad
--- /dev/null
+++ b/docs/architecture/运维/assets/04-冒烟门12项.svg
@@ -0,0 +1,114 @@
+
diff --git a/docs/architecture/运维/assets/06-观测体系.svg b/docs/architecture/运维/assets/06-观测体系.svg
new file mode 100644
index 00000000..6def427f
--- /dev/null
+++ b/docs/architecture/运维/assets/06-观测体系.svg
@@ -0,0 +1,153 @@
+
diff --git a/docs/architecture/运维/assets/08-k3s迁移.svg b/docs/architecture/运维/assets/08-k3s迁移.svg
new file mode 100644
index 00000000..8a6b237b
--- /dev/null
+++ b/docs/architecture/运维/assets/08-k3s迁移.svg
@@ -0,0 +1,161 @@
+
diff --git a/docs/architecture/运维/运维图说.md b/docs/architecture/运维/运维图说.md
new file mode 100644
index 00000000..12cdea57
--- /dev/null
+++ b/docs/architecture/运维/运维图说.md
@@ -0,0 +1,184 @@
+---
+date: 2026-06-22
+topic: 运维域图说——把「部署在哪、怎么变成在跑的服务、靠什么持续看见它」画成一套图 + 讲解(架构图集金样板·运维域首件)
+status: 现行 + 待接(观测)+ 缓做(k3s)三态并存 · 防漂移门记源档 commit hash
+映射源档:
+ - docs/architecture/运维/README.md @ 15b707fd
+ - docs/architecture/运维/观测体系.md @ 3e71715a
+ - docs/architecture/运维/k8s迁移.md @ 15b707fd
+---
+
+# 运维域图说
+
+> **这是什么**:绘境AI 运维域的「看图入口」。运维域回答三件事——这套系统**部署在哪些机器上**、代码**怎么从一行 commit 变成在运行的服务**、靠**什么确认它还活着并且活得够好**。这份图说把这三件事,连同两件「设计已出但还没接上」的事(线上观测体系、k3s 迁移),用一套图加配套讲解画清楚。复杂、跨机的用手绘 SVG 大图,简单、线性的用 Mermaid,已有的图一律单源引用、不复制。
+>
+> **给谁看**:负责部署与值守的工程师、做发版的人、排查线上故障的人,以及关心可用性与运维成本的创始人。判断「这套运维方案是不是想要的那个」看这份图就够建立全局轮廓,逐字节的命令仍去 `deploy/` 脚本与 `.agents/skills/staging-ops.md`。
+
+---
+
+## 0. 阅读约定与同步纪律
+
+- **映射的设计档**:本图说不另立设计,只把运维域三份 canonical 设计档画出来——部署链与四机分工出自 [`运维/README.md`](README.md),线上观测体系出自 [`观测体系.md`](观测体系.md),k3s 迁移出自 [`k8s迁移.md`](k8s迁移.md)。frontmatter 里记了这三份的当前 commit hash,作为**防漂移门**:源档一旦变更、hash 对不上,这份图说与对应 SVG 即标「待复核」,由收口脚本比对。
+- **同步纪律**:**设计一变动,本图说与对应 SVG 必须同步更新**,每张 SVG 脚注注明映射源档与状态。已并入 wave 收口清单。
+- **三种状态贯穿全图,必须看清**:运维域的特殊之处是它同时承载「现行已建」「设计已出待接线」「收窄后缓做」三类内容,绝不能把后两类画成已建。图 6(观测)整体是**接**(待接线)、图 8(k3s)整体是**缓**(缓做、排在 W-G1 之后),其余六张是**现**。每张图内部还会用实心块 / 虚线框 + 「待接线」「缓做」小标把单个元素的状态再标一层。
+- **产物形式**:SVG 入仓(GitHub 与编辑器直接渲染矢量),PNG 在 mini-desktop 转(6c6g 禁 chrome、无转换器)。本图说只出 SVG。
+
+## 1. 全图通用图例
+
+**生产维度徽章**(用小色块 chip + 白字标在每张图相关的维度上,运维域主要关心其中四个):
+
+- **可靠**(`#16a34a`):隔离验证安全变体、备份 JAR 一键回滚、冒烟门退出码可卡口、观测旁路降级、k8s 共存保护与 rollout undo。
+- **可观测**(`#0ea5e9`):OTel 统一采集、Grafana 三联下钻、夜莺告警必达——这是图 6 的主轴。
+- **安全**(`#dc2626`):push 走 Gitea 中转(scp/rsync 被分类器拦)、Collector 集中脱敏、admin 观测入口权限守门不裸暴露后端。
+- **成本**(`#16a34a`):内网物理机 + 人工部署而非重 CI、不硬凑第二台机器上多节点、缓存命中率哨兵——都是 < ¥5,000/月成本盒子的取舍。
+
+(另两个维度 **数据** `#475569`、**伸缩** `#7c3aed` 在 k3s 图上点到:声明式编排与平滑长成多节点 = 伸缩。)
+
+**复用 / 边界三线语义**:
+
+- **实线**(`#334155`):现成直接用、同步动作或命令。
+- **虚线**(`#64748b`,`stroke-dasharray="6 4"`):自建 / 解耦 / 回执 / 待接线 / 缓做的目标态。
+- **双线 / 加粗框**:跨域共享的公共件或需要强调的边界。
+
+> 运维域图说里,虚线还额外承担一层**状态语义**:凡是「待接线」(观测)或「缓做」(k3s)的元素,一律用虚线框 + 文字小标画出,与「现行已建」的实心块在视觉上一眼区分开。这是本域最该守的纪律点——观测体系和 k3s 迁移都是「设计已出、代码未接」,绝不能因为画得好看就让人误以为已经建好了。
+
+---
+
+## 2. 图集
+
+### 图 1 · 四机分工拓扑〔引·现〕
+
+> 单源引用,不复制:四机分工拓扑的 Mermaid 已在 **[运维/README.md §1.1](README.md#11-跑在哪里四台机器各司其职)** 内嵌,是该图的唯一来源。这里只链接、不抄一份进来——同一张图存两处、改一处漏一处,正是这份图集要消灭的漂移面。
+
+这张图回答「服务跑在哪里」。绘境AI 在内网阶段刻意不上云托管、不上 Kubernetes,而是用一组通过 Tailscale 连起来的物理机,按角色硬分工:**lili-mac** 是创作者本地工作站,跑开发主会话与快构建,但它会休眠合盖,所以不进 Tailscale 调度、也不承担任何「门」;**mini-desktop** 是权威验收机,staging 全栈、重型构建、浏览器端到端测试都在这里,且与生产同构;**mini-infra** 是共享基建机,Gitea / PostgreSQL / Redis / MinIO / new-api 都在这台,它绝不跑项目 app 或重型构建;**6c6g** 是常驻无人值守机,跑常开的编排、定时任务、git 操作,但禁跑重活(重型前端构建会 OOM)。
+
+读这张图要抓住一条最硬的边界:**Mac 是 ARM 架构,产出的 JAR 与前端产物架构中立可用,但 Docker 镜像与冒烟门必须在 x86 的 mini-desktop 出**,否则镜像架构与生产不同构,等于半假的门。这条边界在后面图 8(k3s 迁移)里会再次出现并延伸——到了 k8s 时代,「进集群的镜像必须 mini-desktop x86 出」依然成立。这张图没有现行/远期的灰度,它就是当前真相;唯一的「设计缝」其实在别处——README §1.1 自己点明 mini-infra 上跑的关系型库是 PostgreSQL,而 mini-desktop 上是隔离的 staging MySQL,两者不是一回事,端点口径以凭据 SoT《内网凭据与端点.md》为准,别混。
+
+### 图 2 · 部署链:push → pull → 重建 → 验门〔SVG新·时序·现〕
+
+
+
+这张时序图回答「代码怎么变成在跑的服务」。它要先破除一个误解:开发团队版文档里那套「push 触发 CI、自动构建镜像、滚动更新」是**目标态蓝图,与现实系统性脱节**(那份文档顶部自带审计横幅说明这点)。现行的部署没有 docker-compose、也没有自建 CI 流水线,而是**人工经标准序在 mini-desktop 上完成**——图里把它画成四条泳道之间的一串动作,并在底部用一个虚线框单独把这套蓝图标成「现实未建·勿当现状」,免得有人照着蓝图去找不存在的 CI。
+
+核心三步在图上从左到右展开。**第一步同步代码**:代码经 `git push` 推到 Aliyun Gitea(默认远程,SSH `:2222`),mini-desktop 再从同一个 Gitea 以匿名 HTTP `:3000` 拉取(注意是 HTTP 只读端口、不是 SSH)。这里画出了两条已经踩过的坑:直接 `scp / rsync` 源码树会被分类器拦下,所以必须走 Gitea 中转;大资产 push 在途时再发 push 会撞 Gitea 的 ref 锁,所以同仓 push 要串行。**第二步重建**:在 mini-desktop 上 `git reset --hard` 到目标分支、`mvn clean install` 出新的 fat JAR,收口前**以字节码实证**新 JAR 确实含本次改动(曾因「构建源 ≠ 运行的 JAR」翻过车,图上单画一格强调)。**第三步验门**:重启后验 health 200、四模板就绪、Flyway up-to-date,再跑冒烟门(即图 4)。
+
+整张图最该让人看出的,是中间那个橙色虚线框——**隔离验证安全变体**。高风险或整机变更不直接动 live,而是先用新 JAR 在隔离端口 `:48090` 起一个实例验全,**live 的 `:48080` 全程不动**,验全过才切;任一步失败就用 `/tmp` 里的备份 JAR 把 `:48080` 恢复回去。这套「验全才切、失败即回」的安全变体是运维域可靠性的支点,后面图 8 把它原样平移到了 k8s 的隔离端口切换。图底还有一条红线值得记住:**API 全绿 ≠ UI 通**,编排器旁路会掩盖 UI 缺陷,用户可见波次收口前必须另做一次真浏览器 UI 走查。
+
+### 图 3 · 隔离验证安全变体〔Mer新·流程·现〕
+
+这张图把图 2 里那个橙框单独放大,讲清「为什么验全才切、失败怎么退」。它是一条状态/分支流程:新 JAR 不直接顶替 live,而是先在隔离端口 `:48090` 起一个实例,跑完整验证(health、四模板、Flyway、冒烟门 12 项);只有**全部通过**才停旧实例、释放端口、把新实例切到 `:48080`;**任一步失败,立即用 `/tmp` 备份 JAR 把 `:48080` 恢复**,回到改动前的形态,全程 live 不受影响。这条流程让一次高风险发版的下行风险被牢牢兜住——最坏情况也只是「白验一次、live 没动」,而不是「切了一半、服务挂了、退不回去」。
+
+```mermaid
+flowchart TB
+ START["新 JAR 已构建
(字节码实证含本次改动)"] --> ISO["在隔离端口 :48090
起一个新实例"]
+ LIVE["live 后端 :48080
全程不动 · 继续服务"]:::live
+ ISO --> V{"在 :48090 验全?
health 200 · 四模板就绪
Flyway up-to-date · 冒烟门 12 项"}
+ V -- "全过" --> SWITCH["停旧实例 → 释放端口
把新实例切到 :48080"]
+ V -- "任一失败" --> ROLLBACK["/tmp 备份 JAR
把 :48080 恢复回去
(5 分钟内 · live 本就没动)"]:::danger
+ SWITCH --> REVERIFY["切后复验冒烟门
+ 真 UI 走查"]
+ SWITCH -.->|稳定观察一两天后| CLEAN["再删 /tmp 备份 JAR"]
+ ROLLBACK --> BACK["回到改动前形态
排查后重来"]
+
+ classDef live fill:#eff6ff,stroke:#2563eb,stroke-width:2px;
+ classDef danger fill:#fee2e2,stroke:#dc2626,stroke-width:2px;
+```
+
+这张图没有现行/远期边界,它就是现行高风险发版的标准动作;它和图 2 的关系是「图 2 给全链路、图 3 把其中最关键的安全机制放大」。要注意的设计缝只有一个:这套变体是**人工经标准序**执行的,不是声明式的——这正是图 8(k3s)想用 `kubectl rollout undo` 改进的地方,但在 k8s 落地前、乃至落地后的过渡期,这条人工兜底路始终保留。
+
+### 图 4 · 冒烟门 12(+1)项〔SVG新·流程·现〕
+
+
+
+这张图回答「靠什么确认它健康」。每次 staging 部署之后跑一遍 `deploy/smoke-test.sh`——它是「部署后是否健康」的**就绪检查**(秒级、以读为主、可反复跑),逐项 PASS / FAIL,末尾给总判与退出码(0 = 全过,1 = 有 FAIL),所以能直接挂到部署脚本里当卡口。图上把 12 个默认项按「基础设施 / 鉴权 + 五条端到端闭环链路」分组画出来,让人一眼看出冒烟门验的不是零散接口,而是**五条业务链的关键 API 是否都在岗**:① 创作→生成→预览、② 发布→审核→游戏流、③ 试玩→互动→分享、④ 广告→收益→钱包、⑤ 数据回路(遥测→质量分→feed 重排)。
+
+读这张图要抓三个细节。其一,**12 项里唯一的写操作**是建一条无副作用的草稿(`POST /app-api/studio/draft`,status 0、不发布、无下游副作用),用于验证创作入口 + 鉴权 + gameId 分配在岗;其余全是读。其二,`--deep` 才加的第 13 项(图上用橙色虚线框单独标「按需」)走真实写路径,触发一次生成入队 + 遥测落库,默认不跑、只验入队 `200/code=0`,不等生成完成。其三,图上用红框钉死了一个反复出现的坑:**feed 列表项的 `packageUrl` 字段恒为 null**,真实取游戏包要走 `GET /app-api/runtime/package/{versionId}`,别拿 `packageUrl` 当取包入口。
+
+这张图的「设计缝」画在右下角那个虚线框里:冒烟门是「部署那一刻的就绪点检」,它**不是**深度 e2e(深度 e2e 由 agent-loop 编排器批跑,职责不重叠),也**还没有**常态监控来补它的另一半——这正好衔接到图 6 的观测体系。衔接点写在图上:冒烟门那 12 项的结果可以打成指标推给 Prometheus,让「每次部署的健康度」也进可观测历史,而不是只在部署当时的终端里闪一下。
+
+### 图 5 · 可用性 SLO / Error Budget〔Mer新·讲解·现〕
+
+这张图回答「健康到什么程度才算达标」。运维域的硬指标是**服务可用性 ≥ 99.5%**,与之配套的是 MVP 基础设施成本控制在 **< ¥5,000/月**——这两个数字是运维域所有取舍(不上云托管、单体而非微服务、人工部署而非重 CI)的约束来源。图把可用性目标拆成三档 SLO(来自 `security-and-reliability.md` §5.1:游戏流 99.5%/月 ≈ error budget 3.6 小时、AI 生成 99%/月 ≈ 7.2 小时、支付 99.9%/月 ≈ 43 分钟),并点明这些目标怎么落进成本盒子。
+
+```mermaid
+flowchart TB
+ GOAL["可用性目标 ≥ 99.5%(MVP)
+ 基础设施成本 ¥5,000/月以内"]:::goal
+ subgraph SLO["三档 SLO + Error Budget(security-and-reliability §5.1)"]
+ direction LR
+ S1["游戏流
99.5% / 月
容错预算 ≈ 3.6 小时"]
+ S2["AI 生成
99% / 月
容错预算 ≈ 7.2 小时"]
+ S3["支付
99.9% / 月
容错预算 ≈ 43 分钟"]
+ end
+ subgraph COST["成本盒子怎么撑住目标"]
+ direction LR
+ C1["内网物理机
不上云托管"]
+ C2["单体
而非微服务"]
+ C3["人工部署
而非重 CI"]
+ end
+ GOAL --> SLO
+ GOAL --> COST
+ SLO -.->|"现状:只有一个目标数字,
没有东西在持续度量它"| GAP["缺口:error budget 无人消耗与记录
→ 由观测体系落地(图 6)
用 health 成功率算实际可用性 + burn rate 看板"]:::gap
+
+ classDef goal fill:#f0fdf4,stroke:#16a34a,stroke-width:2px;
+ classDef gap fill:#fff7ed,stroke:#d97706,stroke-width:2px,stroke-dasharray:5 4;
+```
+
+这张图最该让人看出的是那条虚线指向的**缺口**:≥99.5% 现在是一个**目标数字**,但没有任何东西在持续度量它、没有 error budget 在被消耗和记录。换句话说,达标线画出来了,举证手段还没建。这个缺口的归宿就是图 6 的观测体系——用 health 探测的成功率算游戏流 API 的实际可用性,对着三档 SLO 做 burn rate 看板和告警,让「达没达标」从一句承诺变成一张有数据、有容错预算余量的看板。所以图 5 和图 6 是一对:图 5 立目标、点缺口,图 6 给落地手段。
+
+### 图 6 · 观测体系:OTel → Grafana / 夜莺〔SVG新·架构·接(设计已出·待接线)〕
+
+
+
+这张图回答「线上靠什么持续观测」——也是本域**最该验状态纪律**的一张。它整体是**接**(待接线):创始人 2026-06-21 定了栈(OTel 统一采集 + Prometheus + Grafana 主看板 + 夜莺主告警),正式设计稿已出,但**代码大半没接、没后端**。所以图上做了一件最要紧的事:把「现在已经有什么」和「还得新建什么」用实心块 / 虚线框严格分开,绝不让人误以为观测已经建好。
+
+图按「采集 → 管道 → 存储 → 看板/告警」一条链画,逐段标状态。**唯一已就位的实心块**在图正下方高亮:aigc-server 已引入 `spring-ai-alibaba-starter-graph-observation`,SAA 裸图每个节点已发 `spring.ai.alibaba.graph.node.` 的 Micrometer observation(带 trace 和耗时,失败反映在指标里)——这是后端唯一一段已经在以标准产出、且依赖已就位的观测信号。但图上同样标清楚:它缺一个把它收走的后端、缺一个非 NOOP 的 `ObservationRegistry`(要 actuator/micrometer 装配在席)。**其余全是虚线框 + 「待接线」**:OTel Java Agent(自动 span,monitor starter 当前根本没进 aigc 部署单元)、五个生成业务指标(`gen_task_total` / `gen_duration_seconds` / `gen_queue_depth` / `gen_gate_fail_total` / `llm_cost`,目前在代码里**全部零命中**,要补 MeterRegistry 注册才有数据,其中成本指标还额外依赖一个尚未落地的 new-api `logs.quota` 采集薄片)、OTel Collector、Prometheus / trace 后端 / 日志后端(trace 倾向 Tempo、日志倾向 Loki,但都标「选型待定」)、Grafana、夜莺、通知通道、admin 观测入口。
+
+读这张图要抓住三层设计意图。其一,**为什么 Collector 居中而不是各组件直连后端**:让每个进程直接推各自后端会把地址、协议、脱敏逻辑硬编码进每个应用,上 k8s 或换后端就得改一圈;中间放一个 Collector 当统一入口,脱敏(手机号/token)、批处理、采样、路由全在这一层集中做,换后端只改 Collector 导出配置、应用零改动——这正是「先单体可跑、后平滑上 k8s」能成立的技术支点。其二,**Grafana 和夜莺不是冗余而是分工**:Grafana 负责「你主动去看时看得清」(三联下钻),夜莺负责「你没在看时它把你叫来」(把 P0–P3 升级链变成真规则真通道,补上「告警通道一根没接」这个最大的空);创始人点名的三类关键告警都在图上有家——可用性走 P0、错误率(5xx>2%)走 P1、生成失败率(<70%)走 P1。其三,图底那条红线是观测体系的底线:**埋点开关默认关、经 profile 显式开,agent 异步批量上报、Collector 不可达时本地丢弃**,硬验收是「停掉 Collector,主链路与各 API 行为不变、冒烟门仍全绿」——观测栈本身挂掉,绝不能影响被观测的服务。
+
+除图上画出的「trace/日志后端选型、admin 嵌入方式与 SSO(详见图 7)」这几条待核外,源档《观测体系.md》§6 还留了两条待创始人拍板的口径,读图时一并记住、别当已定:一是**观测数据保留期与成本**——trace 与 metrics 存多久直接吃 mini-desktop 的磁盘,要对一下账「预算里留的那笔监控冗余够不够这套栈的存储」;二是**生成成功率告警阈值**——现在 P1 写的是「成功率 < 70%」(已经很糟该紧急处理的线),而验收线是 ≥80%,是否要在 70% 之外再加一条 80% 的趋势预警,让成功率从 80% 往下掉时就先有提醒、而不是等到 70% 才报,也待拍。
+
+### 图 7 · admin 观测入口〔Mer新·流程·接(待接线)〕
+
+这张图把图 6 右侧「admin 观测入口」那一块放大,讲清运营怎么从后台一键进监控大盘。它整体也是**接**——而且这块的现状是**零**,要整套新建:`game-admin/src` 下没有任何观测相关的路由、菜单或组件,后端也没有任何给 admin 用的观测查询接口。所以「控制台一键进盘」不是接一根线,而是要补齐前端菜单/路由/组件、后端管理员专属查询接口、嵌入安全处理三件,缺一不可。图用虚线把这三件标成「待接线」,并画出 admin 进盘的链路与那个必须解决的体验问题:**别让运营进个监控还要再登一次 Grafana**。
+
+```mermaid
+flowchart LR
+ OPS["运营
(system_users 已登录 admin)"] --> ADMIN["game-admin 控制台
『观测』菜单(待建)"]:::todo
+ ADMIN -->|"观测大图:嵌入只读大盘"| EMBED["Grafana 嵌入面板
可用性/错误率/生成成功率"]:::todo
+ ADMIN -->|"深挖跳转"| PROXY["admin 后端 auth-proxy
透传 system_users 身份头(待建)"]:::todo
+ PROXY -->|"可信头免登(SSO)"| GRAF["Grafana 完整大盘
trace/metrics/log 三联下钻"]
+ ADMIN -.->|"告警概览 API"| N9E["夜莺告警列表
最近告警 / 值班状态"]
+ EMBED --> GRAF
+
+ classDef todo fill:#fff7ed,stroke:#d97706,stroke-width:1.5px,stroke-dasharray:5 4;
+```
+
+这张图要让人看出两处尚未拍板的设计缝,都还**待核**,不能当成已定。其一,**嵌入方式**:iframe 嵌 Grafana 不是写个 `