docs(arch-atlas): 按领域拆成 00-07 编号文档(全放顶层)——创始人反馈全量主档太大
结构经三次反馈收敛终态:导览式多文件(跨子目录不渲染)→ 合并一篇(太大 1721 行)→ 拆 8 篇编号文档都放 docs/architecture 顶层: - 00-系统总览图说.md = 总图(7 系统级图)+ 目录(链 01-07)+ 通用图例 + 按角色路径 - 01-产品…07-运维图说.md = 每域一篇,各含该域全部图 + 讲解(散文逐字保留) 顶层文档引子目录 assets(运维/assets/xx.svg)单向下引、全图真渲染;SVG/各域README不动。 复验:8 篇共 35 图嵌入零缺失、36 Mermaid 配平、00 链 7 域有效。 配方/记忆/计划/README索引同步终态(铁律:图集文档放顶层引子目录assets,别让子目录文档跨引另一子目录图)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bf461e723a
commit
b52afc5ea2
@ -9,7 +9,8 @@
|
||||
## 产物形态
|
||||
- **混合**:复杂/跨域图 = 手绘 **SVG** 大图(高保真、矢量、GitHub 直渲);简单/线性图 = **Mermaid** 内联。
|
||||
- 每张 SVG 另在 **mini-desktop** 批量转 PNG 入仓(6c6g 禁 chrome、无转换器)。SVG 只在 6c6g 出。
|
||||
- **最终产物 = 单一全量主档** `docs/architecture/系统全图说.md`(总图 + 目录 + 全部图说 inline 在一篇)。**为什么不分多文件**(2026-06-22 创始人反馈纠偏):多文件形态下,顶层/某文档跨子目录引用另一子目录里的 SVG,在部分渲染环境**不显图**;故合并成一份顶层文档。SVG 仍按域留各子目录 `assets/`(产出阶段如 `运维/assets/`、`架构/assets/`),主档经**顶层相对路径**(`运维/assets/xx.svg`、`架构/assets/arch-xx.svg`,apex 系统级图在 `assets/xx.svg`)引用,全部 inline 渲染。各域 `README.md` 是既有设计档、不动。
|
||||
- **最终产物 = 按领域拆分的编号文档,全放 `docs/architecture/` 顶层**:`00-系统总览图说.md`(总图 = 7 张系统级图 + 目录,链各域)+ `01-产品…07-运维图说.md`(每域一篇,各含该域全部图 + 讲解)。SVG 仍按域留各子目录 `assets/`(`运维/assets/`、`架构/assets/arch-`/`sbx-`、`产品/assets/` 等),顶层文档经**顶层相对路径**(`运维/assets/xx.svg`;00 的系统级图在 `assets/xx.svg`)引用、inline 渲染。
|
||||
- **结构演进的教训(2026-06-22 创始人三次反馈收敛,务必照终态做)**:① 起初「导览式 apex(顶层)+ 各域图说(子目录)」——apex 跨子目录**链**各域、子目录文档间互引,在部分渲染环境**不显图**;② 改合并成一份顶层全量主档——**太大**(1721 行,创始人嫌大);③ **终态 = 按领域拆成多篇、都放顶层、文件名编号 01/02/03 排序**——既小而可读,又因「顶层文档 → 子目录 assets」是**单向下引**(渲染没问题,合并版已实证)而全图真渲染。**铁律:图集文档一律放顶层、引子目录 assets;切忌让子目录里的文档去跨引另一子目录的图。**各域 `README.md` 是既有设计档、不动。
|
||||
|
||||
## SVG house style(逐条照做,违一条图废)
|
||||
- 头:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1480 H" font-family="-apple-system,'PingFang SC','Microsoft YaHei',Segoe UI,sans-serif">`,H 按内容 700~960。
|
||||
@ -35,7 +36,7 @@
|
||||
## 编排配方(按域并行)
|
||||
- **每域一个 opus agent**(`agentType: general-purpose`,可 Write),克隆金样板:读 计划稿+金样板 md+2 张金样板 SVG+本域源档 → 逐图产出(SVG/Mermaid/引用)→ 自检 → 汇编 md。结构化返回 `{docFile, svgFiles, figureCount, svgOk, statusDisciplineNote, singleSourceNote, selfCheck, flagsForReview}`。
|
||||
- 多域 = `parallel()` 扇出(不同域不同文件夹、零碰撞,无需 worktree 隔离)。同域两份图说共享 `assets/` 时用文件名前缀区分(如 `arch-` / `sbx-`)。
|
||||
- **合并成单一全量主档**(放最后,关键收尾):各域产出 + 系统级图 → 合进 `系统全图说.md`。规则:逐字保留各域散文、SVG 改顶层相对路径、「引」图 inline 其 README 的 Mermaid(带「(图源:…)」小注)、顶部生成目录锚(GitHub-slug 算法,逐个核命中零断链)。生成引擎子树只链接不并入。**各域中间产物(per-domain `<域>图说.md`)是临时件,合并后删除**(避免与全量主档双份漂移),SVG 留子目录;主档防漂移门改记真实设计档 hash(非中间图说)。
|
||||
- **汇编成 00-07 编号文档,全放顶层**(放最后,关键收尾):各域产出 → `0N-<域>图说.md`;系统级图 + 目录 → `00-系统总览图说.md`(用相对链接指 01-07)。规则:各域散文逐字保留、SVG 用顶层相对路径(`<域>/assets/xx.svg`,00 的系统级图用 `assets/xx.svg`)、「引」图 inline 其 README 的 Mermaid(带「(图源:…)」小注)。生成引擎子树只链接不并入。每篇 frontmatter 防漂移门记该域真实设计档 hash(非中间图说),各图具体映射在图脚注。(若中途产过 per-domain 子目录图说或合并大档当过渡,终态须收敛到这套顶层编号文档、删过渡件,避免双份漂移。)
|
||||
- **分两期降风险**:先六域(自包含、可立全局轮廓),后生成引擎子树(最厚、且常被另一 session 在飞建——**第二期前必先跨 session 对齐边界、只链不双写**)。
|
||||
|
||||
## 复验脚本(主会话亲验,不轻信 agent 自检)
|
||||
|
||||
189
docs/architecture/00-系统总览图说.md
Normal file
189
docs/architecture/00-系统总览图说.md
Normal file
@ -0,0 +1,189 @@
|
||||
---
|
||||
date: 2026-06-22
|
||||
topic: 系统总览图说——绘境AI 架构图集的总图 + 目录(系统级 7 图 + 下钻各域)
|
||||
status: 现行为主(系统级 7 图)· 架构图集入口 · 通用图例与按角色路径在此
|
||||
---
|
||||
|
||||
# 00 · 系统总览图说
|
||||
|
||||
> **这是什么**:绘境AI **架构图集**的**总图 + 目录**——整套图集按领域拆成 8 篇(本篇 00 系统总览 + 01–07 各域,每篇一个文档、各含该域全部图与讲解)。本篇是入口:先读下面七张**系统级跨域图**建立全局轮廓,再按目录下钻到某个领域那一篇。
|
||||
> **怎么读**:先看「系统级 7 图」(系统怎么分层、两条生成轨现行 vs 远期、数据怎么回流、钱怎么转、失败怎么兜、鉴权边界在哪),再按你的角色或任务选某领域下钻(见文末「按角色读」)。所有 SVG 仍在各子目录 `assets/` 下,各篇经相对路径引用、inline 渲染。
|
||||
|
||||
---
|
||||
|
||||
## 各领域图说(目录 · 下钻入口)
|
||||
|
||||
- [01 · 产品图说](01-产品图说.md) — 产品定义 ≠ 建设进度;护城河「不假装有墙」
|
||||
- [02 · 架构图说](02-架构图说.md) — 图 11 契约 5 处现实缝;决策史别当现行
|
||||
- [03 · 产物执行沙箱图说](03-产物执行沙箱图说.md) — 别把机制已建当已安全;两条正交边界别混
|
||||
- [04 · 后端图说](04-后端图说.md) — DB 镜像漂移;桩与真分清;全图无物理外键
|
||||
- [05 · 前端图说](05-前端图说.md) — 试玩宿主机制建成 ≠ 合规收口;同源过渡态三债
|
||||
- [06 · 运营图说](06-运营图说.md) — 元素级被阻塞部分别画成已建;8 项法定 P0 待律所
|
||||
- [07 · 运维图说](07-运维图说.md) — 观测 = 待接、k3s = 缓做,别画成现行
|
||||
- 生成引擎子树(护城河关键路径,内容最厚、正被另一条 session 在飞建设)→ **[生成引擎 README](架构/生成引擎/README.md)**(本图集只链接、不并入;系统级图 3「两条生成轨边界」已给其现行 vs 远期总闸轮廓)
|
||||
|
||||
---
|
||||
|
||||
## 0. 怎么读 + 全图通用图例
|
||||
|
||||
**这份主档的形态,是「先定向、再下钻」。** 它分功能段:第一篇是**系统定向图集**,用七张系统级大图把整个系统的轮廓自顶向下讲清楚;第二到第八篇是**七个领域的全部图说**,把各域的每一张图与每一段讲解都搬进来 inline。建议的读法是:**先把第一篇七张图连讲解读完**(建立全局轮廓),**再按你的角色或当前任务,选某一两个领域的篇章下钻**(文末给了按角色推荐的路径)。读完第一篇,你应该能回答「这是个什么系统、分几层、两条生成轨现行 vs 远期怎么切、数据怎么回流、钱怎么转」;读完某领域那一篇,你应该知道「这块的图在哪、它的命门是哪条缝」。
|
||||
|
||||
**单源纪律(本图集的硬约束)。** 这份图集要消灭的就是「同一张图存两处、改一处漏一处」的漂移面。在原来的多文件形态下,本图集靠「系统级图内联、领域图只链接」来守这条纪律。**本主档是单一全量主档,定位就是把所有图说 inline 在一篇**——所以原各域图说里那种「单源引用、不复制 README 的图,只给链接」的声明,在本文里改成**直接内联该 README 对应节的 Mermaid 块**(让它真渲染),并在图下注明图源;原「单源不复制」的声明段相应删去。系统级图与领域图仍是**互补、不重复**:领域图回答「这一块内部长什么样」,系统级图回答「这些块如何跨域串成一个整体」;本文不会把同一张图在不同篇章各画一份。
|
||||
|
||||
**同步纪律 + 防漂移门。** 设计档一变动,本主档与对应 SVG 必须同步更新。本文 frontmatter 记了全部 8 份图说源档 + 6 份 README(引图 Mermaid 来源)的当前 commit hash 作为防漂移门:任一源档变更、hash 对不上,本文与对应 SVG 即标「待复核」,由收口脚本比对。每张 SVG 的映射源档与状态在其所属篇章的散文与状态表里注明。
|
||||
|
||||
**现行 vs 远期 / 已废,严格标注。** 全文凡涉及未来式或被推翻的方案,一律用虚线框 + 文字小标画出,与「现行已建」的实心块一眼区分。几类边界必须看清:**远期·待 spike**(tier2 富游戏自治轨 = AgentScope + Phaser——只有设计、未落代码,绝不画成现行已建)、**future-state**(Nacos / RocketMQ 框架自带但 MVP 未部署、k3s 缓做、观测体系待接线、两条生成线远期可能收敛为一条)、**已废**(Dify / OpenGame 从未部署降远期、玩法填参式模板与 15KB 红线已废除)、**终态迁移中**(廉价线产物的终态定为 `src/` 源项目,现行的声明式 gameDefinition JSON 只是通往它的中间脚手架、正迁移成直接生成 `src/`)。把这些诚实画出,正是为了让据图 review 的人不会把演进中或已废的方案误当现行。
|
||||
|
||||
**产物形式。** 系统级 SVG 入仓(GitHub 与编辑器直接渲染矢量),PNG 在 mini-desktop 批量转(6c6g 禁 chrome、无转换器);Mermaid 图 GitHub 直接渲染、无需转换。本文不转 PNG、不动任何 SVG 文件、不碰生成引擎子树。
|
||||
|
||||
### 全图通用图例
|
||||
|
||||
整套图集(含本主档)共用一套视觉约定,读任何一张图都按这套理解。
|
||||
|
||||
**生产维度徽章**(用小色块 chip + 白字标在每张图相关的维度上)。七个维度对应七种「这套设计在为什么负责」:
|
||||
|
||||
- **安全**(`#dc2626`):iframe 沙箱 + CSP 红线、权限只在后端可信边界强制、打款 fail-fast 绝不发假钱、上游 API key 不裸暴露。
|
||||
- **可观测**(`#0ea5e9`):四路信号(Metrics / Traces / Logs / Errors)+ SAA 节点 observation——但落地态是「接」(待接线),详见运维域。
|
||||
- **可靠**(`#16a34a`):幂等矩阵、最终一致 + 补偿、SLO + Error Budget、多通道兜底——涉及外部模型 / 异步 / 支付,可靠性必须前置。
|
||||
- **成本**(`#16a34a`):复用 Huijing 买现成后台、便宜模型直出、单 key 入计费台账、内网物理机不上云——都是「5 人小团队 + ¥4,300/月」跑起来的取舍。
|
||||
- **数据**(`#475569`):契约即跨端数据边界、推荐用信号驱动排序、行为数据回流「越用越聪明」——数据口径对不对,是系统能不能闭环的根。
|
||||
- **伸缩**(`#7c3aed`):单体平滑长成微服务、Redis 候选集适配无限流、声明式编排平滑长多节点。
|
||||
- **质量**(`#15803d`):harness 九门兜底、三层约束框架、error_rate 硬降权保可玩底线——质量是设计进去的,不是 LLM 自评。
|
||||
|
||||
**复用 / 边界三线语义**:
|
||||
|
||||
- **实线**(`#334155`):现成直接用、同步动作、单向依赖或数据流的正向推进。
|
||||
- **虚线**(`#64748b`,`stroke-dasharray="6 4"`):自建 / 解耦 / 远期 / 待接线 / 决策史的目标态或对照态;远期·待建项用紫色 `#7c3aed`,失败 / 资金红线分支用红色 `#dc2626`。
|
||||
- **双线 / 加粗框**:跨域共享的公共件,或需要强调的硬边界(如两条生成轨唯一交汇的公共件、资金硬边界)。
|
||||
|
||||
**状态码**(贯穿全图集):**现** = 现行已建 / 已实测 · **接** = 现行待接线(设计已出、代码未接) · **建** = 待建 · **缓** = 缓做(排在 W-G1 之后) · **F / future** = future-state(框架自带未部署 / 远期轨) · **废** = 决策史对照(被推翻的旧方案)。全文凡远期 / 待接 / 缓做 / 已废的元素一律虚线框 + 小标,绝不画成现行。
|
||||
|
||||
> **各域特有的状态分布**(各篇沿用本图例,这里把各域整体状态分布先汇总一句,各篇开头再展开):**第一篇系统级**=现 ×5、现 + F ×2;**产品**=九图整体「现」(定义层,两处元素级 future-state);**架构**=现 ×10 + 现+史 ×1 + 现+废 ×1;**产物执行沙箱**=现 ×7(机制全建成,四处现状债元素级标注);**后端**=现 ×8(若干设计缝与桩元素级标注);**前端**=现 ×8 + 建 ×1(tier2 承载);**运营**=11 图整体「现」(元素级 mock / 待建 / 待律所诚实区分);**运维**=现 ×6 + 接 ×2(观测) + 缓 ×1(k3s)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 第一篇 · 系统总览(7 张系统级图)
|
||||
|
||||
下面七张图是这份主档的核心。它们都是**跨域才画得出、没有任何单个领域拥有**的系统级图。按「先看全局形状、再看两条生成轨、再看数据与钱与可靠性与边界」的顺序读下来,就能自顶向下建立对整个系统的认知。
|
||||
|
||||
> 本篇内联的图 1–6 是顶层 `docs/architecture/assets/` 下的系统级 SVG(路径保持 `assets/xxx.svg`);图 7 是 Mermaid,直接内联。
|
||||
|
||||
### 图 1 · 六域生命周期全景〔SVG·架·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答最顶层的问题:**绘境AI 是个什么系统,它的六个领域如何串成一条主线**。设计文档按产品生命周期的六个领域组织——产品(用户要给谁、给什么)、架构(用什么技术、怎么搭)、后端与前端(并列的实现层,同受架构约束)、运营(合规上线、变现、发行)、运维(部署、健康、可用性)。这六域不是六个互不相干的孤岛,而是一条**接力链**:产品定义出「做什么」,架构据此定「怎么搭」,前后端把它实现出来,运营让它合规变现,运维让它持续跑得住。
|
||||
|
||||
读这张图要抓住三件事。其一,**它是一条闭环、不是六个孤岛**——判断「系统有没有缝」,就是看相邻两域的交接处对不对得上;一个具体的例子是后端定义的五条业务链(创作 / 发布 / 试玩 / 广告收益 / 数据回路)恰好就是运维冒烟门按链分组点检的那五条,两域在这个接口上必须严丝合缝。其二,**它不是瀑布,是带回流的循环**——图上方那条贯穿全宽的大虚线,是玩家行为加收益数据回流、反哺产品优先级与生成质量的飞轮;正是这条回流把一条线性的价值链弯成了一个循环,也正是数据与网络效应护城河的来源(它的机制细节在图 4 展开)。其三,**单源纪律**——本图只画「六域如何串成一条生命周期」,六域各自内部的图都在各自的篇章里,本系统图绝不重画任何一张领域已有的图。看完这张图,你就知道了整个系统的骨架和「每一块在哪」;接下来六张图把这条骨架的关键段一段段放大。
|
||||
|
||||
### 图 2 · 六层技术分层总图〔SVG·架·现 + F〕
|
||||
|
||||

|
||||
|
||||
这张图回答「这套系统在技术上**怎么搭起来、分几层**」——是系统级的权威分层视图。一个用户从浏览器进来,自上而下穿过六层:**接入层**(CDN / Nginx)→ **前端应用**(studio + admin)→ **网关层**(Spring Cloud Gateway,MVP 下软转发)→ **业务服务层**(13 个游戏业务模块,jar 聚合进 Huijing 单体)→ **基础设施层**(Huijing 原生的 system / infra / bpm,开箱即用)与并列的 **AI 生成层**(SAA 编排 → new-api → 便宜 LLM → 九门,配 LittleJS 引擎)→ 最底的**中间件层**(MySQL / Redis / MinIO);整套之外,一条**旁路可观测层**横向监控。
|
||||
|
||||
这张图最该让人抓住的,是它那条贯穿始终的设计取向:**先简后扩、能复用就不自研**。后端复用 Huijing 现成的 60% 后台能力、生成不自研大模型而接通用模型、引擎不自研而用成熟的 LittleJS——正是这条取向让系统能用很小的团队和很低的成本跑起来。同时有两处状态边界必须按标注读、绝不能误当现行已建:**其一,中间件层的 Nacos / RocketMQ 是框架自带、MVP 未部署**(图上虚线 + 「future」),所以凡涉及「异步 MQ」「服务注册发现」的设计,在 MVP 阶段都按「进程内调用 / 本地配置」折算;**其二,整条旁路可观测层整体是「接」(待接线)**——唯一已就位的实心块是 SAA 节点 observation,其余 OTel 采集、Prometheus、Grafana、夜莺、admin 观测入口全部待接,落地全貌见运维图 6。这张图给的是空间感:看「某块技术落在哪一层、它现行还是 future」用它;看某一层内部的细节(13 模块怎么聚类、生成层怎么编排)去对应领域篇章。
|
||||
|
||||
### 图 3 · 现行 SAA 廉价线 ‖ 远期 tier2 自治轨 边界〔SVG·架·现 + F〕
|
||||
|
||||

|
||||
|
||||
这张图是看清「生成引擎现行 vs 远期」的**总闸**,也是本主档最该守状态纪律的一张。绘境AI 有两条生成轨:**左轨是现行的 SAA 廉价线**——已实测合入主干,承载超休闲档(打砖块 / 合成 / 挂机 / 答题 / 网格点选),一条流水线从「创作者一句话」经 SAA 裸图编排(Java·16 节点)、new-api 网关、便宜 LLM、harness 九门兜底,到 emit 出包,用 LittleJS 当引擎、产物是一份可维护的 `src/` 源项目;**右轨是远期的 tier2 富游戏自治轨**——待 0 号 spike、未落代码,承载 premium 富游戏(经营 / 合成 / 多系统富交互),走的是与左轨正交的另一套范式:AgentScope(Python)的自治 ReAct agent、作为一个独立 service 跑、用 Phaser / Pixi 全无头引擎、靠三层校验当确定性地板加人工终审兜底,产物是 Phaser 的 `src/` 源工程。两轨**只经公共件交汇**:计费平面、送审 + feed、验收基线 + 执行沙箱、控制 / 管理面治理层。两轨**远期有可能收敛为一条**——把左轨的 SAA + LittleJS 也并入 AgentScope 自治范式(登记为未来方向,当前不做)。
|
||||
|
||||
读这张图,**最要紧的是把左轨的实心和右轨的紫色虚线分清**:左轨是「现行已建」,右轨是「远期·待 spike」,图上用虚线框 + 「远期·待 spike」标死,绝不能因为画出来了就误以为 tier2 已经在跑。还有三层意思必须读到。其一,**左轨的现行真实状态要诚实说清**:骨架立住、控制流确定、九门很硬已合入主干,但生成质量尚未稳定到 80% 门(便宜模型天花板,实测约 60%)、一部分策略被焊进机制代码;范式侧的终态产物定为可维护的 `src/` 源项目(改源不改包),现行 generate 产出的 gameDefinition JSON 只是通往它的中间脚手架、产线正把它迁成直接生成 `src/`(仍在落地,以生成引擎子树最新裁定为准);默认产线切换交 W-G1 把质量做到 80%(dispatcher flag 已存在,一行 flip)。其二,**为什么两轨不合并**:左轨声明式有向图与右轨命令式循环是两种正交范式,硬塞就成项目明令反对的「缝合设计」,而且对卡 80% 门,图的确定性本就比口头督促更稳。其三,**它们的唯一交汇面是公共件**——tier2 换的是「游戏内容怎么造出来」,换不掉「造出来之后怎么被关进笼子跑、怎么计费、怎么送审发行」。生成引擎的深度(SAA 16 节点拓扑、加节点法、救场阶梯、引擎运行时、tier2 详设)在生成引擎子树,本图只画两轨硬边界。
|
||||
|
||||
### 图 4 · 跨域数据流(越用越聪明)〔SVG·流·现〕
|
||||
|
||||

|
||||
|
||||
这张图把图 1 那条「回流大虚线」放大,回答「平台**靠什么越用越聪明**」。它是一条数据飞轮回路:玩家在 feed 玩、互动(①)→ 游戏内 SDK 埋点上报(②)→ telemetry 入库聚合(③,逐事件 uk_event_id 幂等防重)→ 算出 0–100 的质量分(④)→ 进推荐打分公式与 Redis 候选集(⑤)→ feed 重排下发(⑥)→ 回到①,玩家刷到更好的游戏。这条回路转一圈,好游戏自然浮上来、差游戏沉下去,数据回流持续校准推荐。
|
||||
|
||||
这张图最该让人看清的有三点。其一,**error_rate 是唯一的「硬」降权**——技术上跑不动的游戏直接沉底,这条把「好不好玩」之前先卡住「能不能玩」,是可玩性底线。其二,**这条回路就是护城河第一层**——它是数据壁垒加网络效应的产品载体:真实流量积累出来的质量信号无法购买,飞轮转起后追赶成本指数级增长;竞品做生成工具止步于出包,没有这条回流就不「越用越聪明」。其三,**有两处现状要诚实标**:候选集当前可直查 MySQL、Redis 是增长期形态,游标分页目前是桩(永远返回第一页)——公式和飞轮是设计真相,落地仍是增长期的事;而飞轮的第二半(收益 / 留存数据回流成训练语料、反哺生成质量)是远期·待建,现行只覆盖了生成侧自增强这一半,图上用虚线把它和现行回路分开。这张图与图 1 是一对:图 1 点出「有这么一条回流」,图 4 把回流的每一站和它的现状画清。
|
||||
|
||||
### 图 5 · 失败 / 降级 / 补偿路径全景〔SVG·流·现〕
|
||||
|
||||

|
||||
|
||||
这张图是**据图做评审最容易发现「缝」的一张**。它横切三类不可控调用——外部模型(链路 A)、异步任务 / 跨表(链路 B)、支付 / 打款(链路 C)——把「超时 → 失败 → 重试 → 幂等 → 补偿 → 兜底」这条可靠性主线集中画出来。链路 A 给生成调便宜 LLM 的全路径:超时 120s、状态机显式建 FAILED / TIMED_OUT 边、重试加 repair→escalate 救场阶梯、idempotency_key 去重、giveup 留证据,并标出 2026-06 已真实发生的「二厂系通道全废 → new-api 多通道兜底」。链路 B 给异步与跨表:最终一致 + 补偿(非分布式事务)、唯一一处真原子发布(project 把合规裁决 + 出包 + 入流串成事务)、补偿 job 兜底、幂等四范式。链路 C 给钱的事:账户恒等式永远成立、「发起 ≠ 终态」、双路驱动 + CAS、对账锚点链。
|
||||
|
||||
这张图最该让人记住的,是底部那条**关键反差**:打款的降级口径与生成 / 广告**正好相反**——广告渠道缺失降级 mock 可接受(少算收入),但打款渠道缺失若降级 mock 就是吞真钱,必须 fail-fast、绝不发假钱;审核降级则一律朝保守(阿里云超时降到 review、绝不降到 pass)。图底那张「据图 review 的六条检查清单」是这张系统级图存在的意义:每个外部 / 异步 / 资金动作是否都有幂等键、失败是否在状态机里显式建边、补偿 job 是否扫得到、降级方向对不对、抽象是否做对(mock ↔ 真实现可零改业务码切换)、对账锚点链是否端到端串得起来——凡有一格答不上,就是一处可靠性裂缝,据图就能定位,不必逐文件翻。图上也诚实标了打款 mock 桩、订阅自助购买被支付闸门阻塞这些现状缺口。
|
||||
|
||||
### 图 6 · 端到端鉴权信任边界总图〔SVG·架·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「权限在系统的**哪一层、挡什么**」,是系统级的信任边界视图。一个请求从前端经网关到业务,三层各管一段:**① 前端**的路由守卫只改善体验(anon_id 让 Feed / Play / Share 匿名可达、即刷即玩不挡门),但它挡不住直连 API——前端守卫形同虚设,任何「前端藏了按钮就安全」的想法都击穿信任;**② 网关**在 MVP 单体下只做软转发(剥除外部伪造的 login-user 头、有 token 才注入可信头、无 token 也放行),它本身没有路径级 RBAC,所谓「网关双重校验」是微服务拆分后的未来态;**③ 业务服务 huijing-server 是权限的唯一真强制点**——TokenAuthenticationFilter 校验 token 的 userType 与 URL 前缀一致,然后 B 端走声明式 RBAC(@PreAuthorize + 角色菜单交集)、C 端走 Service 归属隔离(eq 谓词把当前用户钉进 WHERE),再叠一层创作白名单(A2 内测准入)和匿名读三纪律。
|
||||
|
||||
这张图与后端图 7 是**互补、不重复**的:后端图 7 是模块类图(讲两套权限模型在代码里的类与方法),本图是**系统边界**(讲前端→网关→业务三层各挡什么、职责怎么切分)。它最该让人看清的,是那条贯穿全图的铁律——**权限只在后端可信边界强制,前端拦截一律不算数**;以及职责切分的本质:网关做「身份可信化」(把不可信外部头换成可信内部头),但绝不替代服务侧的权限判定,两者是接力、不是冗余。anon_id 让玩家免登消费,但创作 / 写域必须越过后端这道墙。图上还诚实标了一处现状:控制器注释里「网关 + 服务端双重校验」是未来态,当前单体下网关甚至不在请求路径上,权限强制 100% 在服务侧单点;mock 后门是 staging 现状、生产必须关死的红线。
|
||||
|
||||
### 图 7 · 角色 × 端全景〔Mermaid·讲·现〕
|
||||
|
||||
这张图回答「**谁在哪个端做什么**」。绘境AI 把「用户」收敛成六种角色,分布在两个前端(C 端 studio / B 端 admin)上;最容易混的一对是「经营」和「运营」——**经营 = 创作者看自己作品的数据**(留存 / 完玩 / 广告转化),**运营 = 平台管理员**(审核 / 精选 / 封禁 / 经营看板),两者在需求清单里分属不同的域(OPS vs OPN),混了就会把功能归错端。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph C端["C 端 · game-studio(Vue3 + Vant)"]
|
||||
direction LR
|
||||
CR["创作者<br/>一句话生成 / 预览迭代<br/>发布 / 看收益(经营)"]:::role
|
||||
PL["玩家<br/>刷 feed 即点即玩<br/>点赞分享 / 发起同款"]:::role
|
||||
CB["B 端客户(询单侧)<br/>提需求 / 看 demo / 验收"]:::roleb
|
||||
end
|
||||
subgraph B端["B 端 · game-admin(Vue3 + Element Plus)"]
|
||||
direction LR
|
||||
OPN["运营(平台管理员)<br/>内容审核 / 精选推荐<br/>封禁处置 / 经营看板"]:::roled
|
||||
ADM["管理员<br/>用户管理 / 权限角色<br/>合规处置 / 数据看板"]:::roled
|
||||
BD["商务 / BD<br/>B 端定制单据流转<br/>报价 / 进度 / 交付"]:::roled
|
||||
end
|
||||
COM["通用(任意端可触)<br/>账号 / 登录 / 消息通知 / 政策页 / 申诉"]:::common
|
||||
|
||||
CR -->|产出可玩游戏| PL
|
||||
PL -.->|发起同款 → 变创作者(P-FED-12)| CR
|
||||
CB -.->|线索 → 单据| BD
|
||||
OPN -.->|审核 / 降权联动| PL
|
||||
ADM -.->|白名单置位 set-creator| CR
|
||||
C端 --- COM
|
||||
B端 --- COM
|
||||
|
||||
classDef role fill:#eff6ff,stroke:#2563eb,stroke-width:2px;
|
||||
classDef roleb fill:#f5f3ff,stroke:#7c3aed,stroke-width:1.6px;
|
||||
classDef roled fill:#fefce8,stroke:#ca8a04,stroke-width:2px;
|
||||
classDef common fill:#f1f5f9,stroke:#475569,stroke-width:1.6px;
|
||||
```
|
||||
|
||||
这张图最该让人看出的,是**两条跨角色的转化回路**:一条是玩家「发起同款」跳转工作坊变成创作者(P-FED-12)——它把「玩游戏的人」转化成「做游戏的人」,是网络效应护城河的产品载体;另一条是 B 端客户的询单经商务 / BD 流转成定制单据。还有一处系统级衔接:运营对内容的审核 / 降权处置会联动 feed 曝光(影响玩家看到什么),管理员对创作者的白名单置位(set-creator)决定一个 C 端用户能不能创作——这两条「B 端动作影响 C 端体验」的链路,正是图 6 那条「权限在后端强制」与图 4 那条「feed 重排」的人侧投影。这张图没有现行 / 远期的灰度,它是当前的角色与端的真相;每个角色的完整旅程(创作者旅程、玩家旅程)在产品篇,每个端的视图地图在前端篇。
|
||||
|
||||
> **第一篇状态分布**:现 ×5、现 + F ×2(图 2 含 future-state 中间件与「接」可观测、图 3 含远期 tier2 轨)。系统级图与领域图**互补不重复**:本 7 图都是跨域才画得出、无单域拥有的图。**远期/已废标注**:tier2 轨(图 3,= AgentScope+Phaser)= 远期·待 spike 虚线、远期可能与左轨收敛为一条;Nacos/RocketMQ(图 2)= future-state 未部署;观测(图 2)= 接;收益回流语料(图 4)= 远期·待建;打款 mock(图 5)= 现状桩;网关双校验(图 6)= 未来态;Dify/OpenGame/玩法填参模板/15KB = 已废;gameDefinition JSON 数据壳 = 中间脚手架·正迁移成直接生成 `src/` 源项目;均不画成现行终态。
|
||||
|
||||
---
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 末尾 · 按角色读:推荐下钻路径
|
||||
|
||||
读完第一篇系统定向图、再按你的角色选某一两个领域篇章下钻,是最省时的读法。下面给四类角色各推荐一条 2–3 个篇章的路径(因各域图说已并入本文,下面的链接都是本文内部锚点)。
|
||||
|
||||
- **产品 / 运营 / 投资人**:先读第一篇 [图 1(六域生命周期)](#图-1--六域生命周期全景svg架现)+ [图 4(数据飞轮)](#图-4--跨域数据流越用越聪明svg流现)+ [图 7(角色×端)](#图-7--角色--端全景mermaid讲现),建立「这是个什么系统、靠什么越用越聪明」的轮廓;再下钻 [第二篇产品域](#第二篇--产品域)(产品定义与护城河)→ [第七篇运营域](#第七篇--运营域)(合规上线 / 变现 / 发行,尤其图 9 备案锁、图 10 钱流、图 11 审核台)。命门:护城河「不假装有墙」、变现被日历闸门阻塞的部分别当已建。
|
||||
|
||||
- **工程师(新加入)**:先读第一篇 [图 2(六层分层)](#图-2--六层技术分层总图svg架现--f)+ [图 3(两条生成轨边界)](#图-3--现行-saa-廉价线--远期-tier2-自治轨-边界svg架现--f)+ [图 6(鉴权边界)](#图-6--端到端鉴权信任边界总图svg架现);再下钻 [第三篇架构域](#第三篇--架构域)(尤其图 11 契约现状)→ 你负责的模块在 [第五篇后端域](#第五篇--后端域)(图 5 ER + 图 6 五条业务链)→ 若做生成主线直接进 [生成引擎子树](#第九篇--生成引擎子树另一-session-在飞只链不并)。命门:契约 DB 镜像漂移、网关双校验是未来态、桩与真要分清。
|
||||
|
||||
- **前端工程师**:先读第一篇 [图 6(鉴权信任边界,前端那一层挡不住直连)](#图-6--端到端鉴权信任边界总图svg架现)+ [图 7(角色×端)](#图-7--角色--端全景mermaid讲现);再下钻 [第六篇前端域](#第六篇--前端域)(图 2 token 两层 + 组件库四层、图 8 真实试玩宿主)→ 跨到 [第四篇产物执行沙箱](#第四篇--产物执行沙箱)(图 8 宿主侧的安全隔离纵深)。命门:试玩宿主「机制建成 ≠ 合规收口」、同源过渡态三债一起收。
|
||||
|
||||
- **安全 / 可靠性评审**:先读第一篇 [图 5(失败 / 降级 / 补偿全景,据图 review 六条检查清单)](#图-5--失败--降级--补偿路径全景svg流现)+ [图 6(鉴权信任边界)](#图-6--端到端鉴权信任边界总图svg架现);再下钻 [第四篇产物执行沙箱](#第四篇--产物执行沙箱)(三层封堵 + 两条正交边界)→ [第五篇后端域](#第五篇--后端域)图 7(鉴权双模型)→ [第七篇运营域](#第七篇--运营域)图 10(打款 fail-fast)。命门:降级方向(可降 mock vs 必须 fail-fast)、权限只在后端可信边界强制、同源红线过渡态。
|
||||
|
||||
### 第九篇 · 生成引擎子树(另一 session 在飞、只链不并)
|
||||
|
||||
生成引擎是绘境AI 护城河的关键路径,内容最厚、单独成一棵子树。它回答「一句话怎么变成一款可上线的游戏」这条技术主线:现行那台被刻意设计成可靠的、固定相位的生成机器(便宜模型驱动 + 确定性图编排约束控制流 + 九门 harness 兜底),以及它要往哪走的演进路线、贯穿全程的范式原则(游戏是长生命周期源项目、LLM 是它的工作室)。本主档的第一篇图 3 已给出「两条生成轨现行 vs 远期」的总闸轮廓,这棵子树是它的深度展开。
|
||||
|
||||
读这棵子树最该带着一条**范式定性**:这套「便宜模型 + 受限 schema + 九门验收」是一条**为超休闲轻游戏(Tier0)量身打造的可靠产线,而不是一个通用生成范式**;它最大的风险不在工程层,而在被当成通用范式去对标 demo 里那一档富交互游戏(那一档结构性地够不着,必须显式分层、复杂品类另开一轨)。子树内现行结论可能随产线化 plan(把现行的 gameDefinition JSON 中间脚手架迁成直接生成 `src/` 源项目)的推进变化,以最新裁定为准。
|
||||
|
||||
> **跨 session 协调红线 + 链接(只链不并)**:生成引擎子树正被**另一条 session 在飞建设**,本主档对它**只链接、不并入其内部图与散文**——它的两簇(现行 SAA 廉价线 / 远期 tier2 自治轨)的逐张图、SAA 16 节点拓扑、九门逐门、tier2 详设都在子树内,本文不重复承载。
|
||||
>
|
||||
> **入口链接** → [`架构/生成引擎/README.md`](架构/生成引擎/README.md)
|
||||
|
||||
---
|
||||
|
||||
> **全文防漂移门汇总**:本文 frontmatter 记了各域设计档(6 域 README + 架构 13模块/契约总览/产物执行沙箱、后端 数据模型/鉴权与权限、运维 观测体系/k8s迁移、生成引擎 README 等)的 commit hash;每图的具体映射源档另见正文该图脚注 / 内联小注。任一源档变更、hash 对不上,本文与对应图即标「待复核」,由收口脚本比对。**SVG 不动**:本文不动任何 SVG 文件,只经顶层相对路径引用它们;PNG 后续在 mini-desktop 批量转(6c6g 禁 chrome),Mermaid 图 GitHub 直接渲染、无需转换。
|
||||
207
docs/architecture/01-产品图说.md
Normal file
207
docs/architecture/01-产品图说.md
Normal file
@ -0,0 +1,207 @@
|
||||
---
|
||||
date: 2026-06-22
|
||||
topic: 产品图说——绘境AI 架构图集(按领域拆分·01)
|
||||
status: 现行为主 · 每图具体映射源档见该图脚注 / 内联小注 · 通用图例见 00-系统总览图说
|
||||
---
|
||||
|
||||
# 01 · 产品图说
|
||||
|
||||
> 本篇是绘境AI **架构图集**的一部分(全 8 篇:[00 系统总览](00-系统总览图说.md) + 01–07 各域)。**通用图例、状态码、按角色读路径见 [00 · 系统总览图说](00-系统总览图说.md)**。
|
||||
> **本域命门(最该据图 review 的设计缝)**:产品定义 ≠ 建设进度;护城河「不假装有墙」。
|
||||
|
||||
---
|
||||
|
||||
> **本域讲什么故事**:产品域只回答一件事——这个产品对用户提供什么(WHAT),不碰「用什么技术实现」。它的九张图从最顶层的「做得出 → 有人玩 → 赚到钱」闭环讲起,展开成 19 个产品域归拢的五大块,讲清 155 条需求怎样收敛成 55 条 P0(MVP 验收口径)、产品需求与技术模块之间那张唯一的多对多映射矩阵(RTM),再落到创作者与玩家两条旅程,最后到商业定位与护城河。读完这个域,你知道「这个产品到底要给谁、给什么」。
|
||||
>
|
||||
> **最该据图 review 的命门缝**:产品域是**定义层、不是建设层**。评审时最该盯两处诚实纪律:**第一,产品定义 ≠ 建设进度**——55 条 P0 是验收口径,不等于今天都真端到端,真实完成度以需求模块映射的现状快照与 MVP 进度总账为准;**第二,护城河话术的红线是「不假装有墙」**(图 9)——四层护城河是要在窗口期点燃的、不是已有的;以及第二条生成轨(tier2)在 19 域里是 future,未落代码、尚无正式 P-id,绝不能画成 MVP 范围。
|
||||
|
||||
> **本域阅读约定与同步纪律**:本图说不另立设计,只把产品域五份 canonical 设计档画出来——产品闭环与 19 域归类出自 `产品/README.md`,155 条需求与编号体系出自 `需求清单.md`,需求↔模块的多对多映射出自 `需求模块映射.md`,商业定位与竞争格局出自 `商业定位.md`,对外护城河口径出自 `护城河话术.md`。frontmatter 里记了这五份相关源档的当前 commit hash,作为防漂移门。设计一变动,本图说与对应 SVG 必须同步更新。
|
||||
|
||||
> **本域状态分布**:产品域是**定义层**而非建设层——它描述的是「产品要提供什么」,不是「代码建到了哪一步」,所以**九张图整体状态都是「现」**(即「这是当前认定的产品定义」),与运维域那种「现行/待接/缓做」三态并存的情况不同。但有两处必须用元素级虚线标清楚、绝不能画成已落地的 MVP 范围:一是**第二条生成轨(tier2 富游戏轨)**,它是经营/合成/挂机等 premium 品类的承载,目前是待 0 号 spike 验证的假设、未落代码、不在 MVP 的 P0 清单、也不单列正式 P-id;二是**控制面 / 管理面治理层**,两条生成线共用、部分有地基、整体待建。这两处在图 2 与图 5 里都用紫色虚线框 + 「待建 / post-spike」小标与「现行已认定」的实心块区分开。**至于这 55 条 P0 各自的真实代码完成度**(哪些真端到端、哪些半真、哪些还是桩),那是建设进度、不是产品定义,以 `需求模块映射.md` 的现状快照与 `docs/mvp/MVP进度总账.md` §2 矩阵为准,本图说不重复承载、不画成产品图的一部分。
|
||||
|
||||
> **本域徽章**:产品域是定义层,不直接谈安全/可观测/可靠这些运行时维度,所以本域只点到其中两个与「产品价值」最相关的——**数据**(`#475569`):19 域全景与需求映射本身就是产品的数据底座;护城河四层里最硬的第一层也是数据壁垒——玩家行为数据 + 质量评分 + 推荐信号。**质量**(`#15803d`):⭐ 三个 P0 最密集的域(自定义创作 / 发布分发 / 游戏信息流)串起的正是「能生成、能发、能刷到」的质量闭环;这条闭环每一环都真实跑通,是 MVP 不追求功能多、只追求闭环跑通的体现。(唯一例外是图 9 的商业定位,那里「资本效率」天然对应**成本**维度,故在该图点到。)产品域图说里,虚线额外承担一层**诚实纪律**:凡是「未来式 / 待建」的东西(护城河飞轮、第二条生成轨、治理层),一律虚线 + 小标画出,与「现在真有的」实心块一眼区分。这是产品域最该守的纪律点——护城河话术的核心就是「不假装有墙」,任何一处把未来式画成已有,都会击穿信任。
|
||||
|
||||
### 产品图 1 · 产品闭环全景〔引·现〕
|
||||
|
||||
这张图回答最顶层的问题:**绘境AI 到底是什么**。答案是一条闭环——把三件过去彼此割裂的事接成一条链:一个没有任何编程基础的普通人,从一句话出发做出一款能上线、能变现的轻量小游戏(**创作**);玩家在类似短视频的游戏信息流里刷到它、即点即玩(**分发与游玩**);平台通过广告、订阅会员、B 端定制三条线变现,收益与行为数据再回流反哺推荐(**变现与数据**)。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["创作者<br/>一句话 / 选模板"] --> B["AI 生成<br/>可试玩游戏"]
|
||||
B --> C["预览 & 迭代"]
|
||||
C --> D["多渠道发布"]
|
||||
D --> E["游戏信息流<br/>即刷即玩"]
|
||||
E --> F["玩家互动<br/>点赞 / 分享 / 评论"]
|
||||
F --> G["广告 / 内购 / 订阅<br/>变现"]
|
||||
G --> H["收益 & 行为数据"]
|
||||
H --> A
|
||||
H -. "行为数据 → 推荐优化" .-> E
|
||||
```
|
||||
|
||||
*(图源:产品/README.md §1)*
|
||||
|
||||
读这张图要抓住一句话:**这条闭环就是所有产品功能挂靠的主干**。竞品大多停在「生成工具」这一步——做完没人玩、也不赚钱;绘境的差异化不在生成本身,而在把「生成 + 流量 + 变现」串成一条链。图里那条从「收益 & 行为数据」回到信息流的虚线尤其关键:它是平台「越用越聪明」的来源,也是后面图 9 里数据护城河的产品侧投影。这张图没有现行/远期的灰度,它就是当前认定的产品骨架;它与本篇后面所有图的关系是「图 1 给主干,其余八张图把主干的每一段展开」。
|
||||
|
||||
### 产品图 2 · 19 个产品域 × 五大块〔SVG新·架·现〕
|
||||
|
||||

|
||||
|
||||
这张图把图 1 那条线性闭环展开成产品的**全貌**:155 条需求按「用户能感知的能力」聚成 19 个产品域,再归拢成五大块,让人一眼看清这个产品由哪些可感知的能力块组成、它们之间怎么流转。五大块从左到右就是闭环的五个阶段——**创作侧**把游戏做出来(素材/模板/自定义创作/授权 IP/发布,5 个域)、**玩家侧**让游戏被玩到(广场/信息流/社区,3 个域)、**变现侧**把钱赚回来(钱包/付费/广告,3 个域)、**成长侧**让创作者留下来(数据经营/成长/激励/通知,4 个域)、**平台侧**让生态转起来(IP 孵化/B 端/运营/账号合规,4 个域)。块顶之间的实线箭头画出产物流转的主方向:创作侧产出 → 玩家侧消费 → 变现侧回钱 → 成长侧留人 → 平台侧转生态。
|
||||
|
||||
读这张图要抓住三个细节。其一,图上用蓝色高亮块钉死了 **⭐ 三个 P0 最密集的域**:自定义创作、发布分发、游戏信息流——它们是 MVP 闭环的关键环节,「能生成、能发、能刷到」这条最小链全靠它们撑起;其余域多为 P1/P2 的后续加厚。其二,每个域卡片右上角标了该域的优先级密度(P0 / P1 / P0-P1 混合),让人快速判断哪些域是 MVP 必交、哪些是远期。其三,也是本图最该让人看清的**设计缝**:创作侧底部那个紫色虚线框——**第二条生成轨(tier2 富游戏轨)**。当前 19 个域承载的是超休闲档的廉价生成线;经营、合成、挂机这类多系统的 premium 品类不在这条线上,而由第二条生成轨承载,它面向价值更高、产量更低的场景,与超休闲线解耦并存。这一轨目前是**待 0 号 spike 验证的假设、未落代码、不在 MVP 的 P0 范围、也不单列正式 P-id**——所以图上必须用虚线把它和 19 个实心域块严格区分,绝不能让人误以为它已是 MVP 的一部分。它的完整设计在架构域生成引擎子树,本图只挂一个边界注脚。
|
||||
|
||||
### 产品图 3 · 155 → 55 P0 收敛〔引·现〕
|
||||
|
||||
这张图回答「MVP 到底做多少」。完整产品有 155 条需求分布在 19 个域,MVP 阶段不全做,而是聚焦其中 **55 条 P0**——它们刚好串起一条「种子用户可试用的全链路」:创建 → 生成 → 预览 → 发布 → 信息流 → 游玩 → 互动 → 广告 → 收益。这张图最该让人记住的,是它背后那条产品哲学:**MVP 不追求功能多,而追求这条闭环每一环都能真实跑通**;P1/P2 是闭环跑通之后的加厚,不是 MVP 的考核项。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
P155["155 条产品需求<br/>(完整产品)"] --> P55["55 条 P0<br/>(MVP 验收口径)"]
|
||||
P55 --> LOOP["覆盖全链路闭环<br/>create → play → earn"]
|
||||
```
|
||||
|
||||
*(图源:产品/README.md §4)*
|
||||
|
||||
这条「155 选 55」的收敛口径,是理解整个产品域优先级的总开关——图 2 里 ⭐ 标记的三个 P0 密集域为什么最硬,正是因为它们贡献了这 55 条里最关键的那些环。要注意的设计缝在于:55 这个数字是**产品验收口径**(哪些功能 MVP 必须可验收),不是**建设完成度**(这 55 条各自代码建到了哪一步)。两者是两回事——某条 P0 在产品口径上「必交」,不等于它今天已经真端到端;真实完成度以需求映射的现状快照与 MVP 进度总账为准(详见本域状态约定的纪律说明)。
|
||||
|
||||
### 产品图 4 · 需求编号体系〔Mer新·讲·现〕
|
||||
|
||||
这张图讲清「怎么读懂一条需求」。需求清单里每一行是一条产品功能,带四个属性;第一次接触的人只要会拆这四个属性,就能读懂整份清单。**编号** `P-{域}-{序号}` 把每条需求挂到它所属的产品域(域用三字母缩写,MAT 素材 / TPL 模板 / CRT 创作……);**端** 说明这条功能服务谁(创作者 / 玩家 / 经营 / 运营 / B 端 / 通用——其中「经营」特指创作者查看自己作品的数据,与「运营」即平台管理员不是一回事,这是最容易混的一对);**优先级** 区分 P0(MVP 必须验收)与 P1/P2(后续迭代);**来源** 标这条需求是从早期 demo 原型来的、还是延续既有能力(v2.0)、还是 demo 暴露出的缺口编号(G#)。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
ID["一条需求 = 一行<br/>例:P-CRT-08 生成结果实时预览试玩"]:::id
|
||||
ID --> A1["① 编号 P-{域}-{序号}<br/>P-CRT-08 = 自定义创作域第 8 条<br/>域用三字母缩写"]:::attr
|
||||
ID --> A2["② 端:服务谁<br/>创作者 / 玩家 / 经营 / 运营 / B端 / 通用<br/>⚠️ 经营=创作者看自己数据 ≠ 运营=平台管理员"]:::attr
|
||||
ID --> A3["③ 优先级<br/>P0 = MVP 必须验收(155 里 55 条)<br/>P1 / P2 = 后续迭代"]:::p0
|
||||
ID --> A4["④ 来源<br/>demo = 早期原型出现过<br/>v2.0 = 延续既有能力 · G# = demo 暴露的缺口"]:::attr
|
||||
|
||||
classDef id fill:#eff6ff,stroke:#2563eb,stroke-width:2px;
|
||||
classDef attr fill:#ffffff,stroke:#475569,stroke-width:1.4px;
|
||||
classDef p0 fill:#fef9c3,stroke:#ca8a04,stroke-width:1.6px;
|
||||
```
|
||||
|
||||
这张图没有现行/远期边界,它是一份「读法说明」,本身就是当前真相。它和图 2、图 3 是一组:图 4 教你拆单条需求的四个属性,图 2 把这些需求按域聚成全貌,图 3 用「优先级」这个属性把 155 收敛成 55。要点出的一处易错点已经画在图上——**端属性里「经营」和「运营」必须分清**:经营是创作者侧(看自己作品的留存/完玩/广告转化),运营是平台管理员侧(审核/精选/封禁/经营看板),两者在需求清单里分属不同的域(OPS vs OPN),混了就会把功能归错端、排错期。
|
||||
|
||||
### 产品图 5 · 需求 ↔ 模块 M:N 映射(RTM)〔SVG新·ER·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「一条产品需求由谁实现」——也是产品域与技术域之间唯一的桥。它画的是一张**关系矩阵**(不是面向对象的类图):左侧是产品侧的 155 条需求(按五大块分组的 P-id),右侧是技术侧的 13 个模块(204 条 T-id),中间是这张 RTM(Requirements Traceability Matrix,需求可追溯矩阵),用多对多的连线把两侧关联起来。之所以要单独有这么一张表,是因为产品需求和技术模块**各自高内聚、互不引用**——需求清单不认识 T-id,架构域不认识 P-id;两者之间的多对多对应关系是最容易变动的耦合点,把它单独隔离在这一张表里,**改产品或改模块,只动这一张表**,另一侧纹丝不动。
|
||||
|
||||
读这张图要抓住三层意思。其一,**三个读法标记**:每行一条 P-id,标了它的「首要 owner」(主要负责的那一个模块,问责与排期归属)、「★主」(主要实现这条需求的技术功能,可以是多个 T-id)、「辅」(支撑或兜底的技术功能,常跨模块)。图中央用一行放大的样例把这三层讲透——产品需求「生成结果实时预览试玩」(P-CRT-08)首要 owner 是 runtime 模块,★主靠 T-RT-01 编译 / T-RT-06 渲染容器 / T-RT-07 注入 / T-RT-04 沙箱四个技术功能,辅以 T-STU-07 的 SSE;产品侧完全不需要知道这些 T-id,技术侧也不需要知道 P-id,只有这张表两边都认识。其二,**多对多是双向的**:一个产品域会连多个技术模块,一个技术模块也会被多个产品域连——图上的交叉连线刻意画出这种「网状」而非「一一对应」的关系,这正是为什么必须用一张专门的矩阵、而不能把映射塞进任何一侧。其三,本图最该让人看清的**设计缝**画在中间表底部那个紫色虚线框里:**两块「待建 · post-spike」的映射**——第二条生成轨(tier2 富游戏轨)和控制面/管理面治理层。这两块设计已经成形、但尚未落地,先在 RTM 里挂上指针、免得它们在产品与技术之间悬空;但它们**还没有正式的 T-id 与映射行**,要等 0 号 spike 验证通过后才展开。所以图上用虚线把这两块和 19 个域的实心映射严格分开——它们是「已挂指针、待建设」,不是「已映射、已实现」。
|
||||
|
||||
### 产品图 6 · 五大块产品域关系〔Mer新·架·现〕
|
||||
|
||||
这张图把图 2 里五大块之间那几根块顶箭头单独放大,讲清「产物在五大块之间怎么流转」。如果说图 2 是「五大块各装了哪些域」的静态全貌,这张图就是「五大块之间动态怎么咬合」的流转图:创作侧产出可玩游戏,是整条链的源头;玩家侧消费这些游戏,把「有人玩」坐实;玩家的游玩与互动触发变现侧把钱赚回来;赚到的收益与沉淀的数据反哺成长侧,让创作者看到回报、愿意留下来继续创作;而平台侧作为底座,一边给生态提供 IP/B 端/运营/合规的支撑,一边把数据与收益的回流闭合回创作侧——形成「创作产出 → 玩家消费 → 变现回流 → 创作者留存 → 再创作」的飞轮。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
CRT["创作侧<br/>把游戏做出来<br/>素材/模板/创作/授权IP/发布"]:::crt
|
||||
PLZ["玩家侧<br/>让游戏被玩到<br/>广场/信息流/社区"]:::play
|
||||
PAY["变现侧<br/>把钱赚回来<br/>钱包/付费/广告"]:::pay
|
||||
GRW["成长侧<br/>让创作者留下来<br/>数据经营/成长/激励/通知"]:::grow
|
||||
OPN["平台侧(底座)<br/>让生态转起来<br/>IP孵化/B端/运营/账号合规"]:::plat
|
||||
|
||||
CRT -->|"产出可玩游戏"| PLZ
|
||||
PLZ -->|"游玩+互动触发"| PAY
|
||||
PAY -->|"收益+数据反哺"| GRW
|
||||
GRW -.->|"创作者继续产出(飞轮)"| CRT
|
||||
OPN -.->|"IP/B端/审核/合规 支撑全链"| CRT
|
||||
PAY -.->|"行为数据回流→推荐优化"| PLZ
|
||||
|
||||
classDef crt fill:#eff6ff,stroke:#2563eb,stroke-width:2px;
|
||||
classDef play fill:#f0fdf4,stroke:#16a34a,stroke-width:2px;
|
||||
classDef pay fill:#fefce8,stroke:#ca8a04,stroke-width:2px;
|
||||
classDef grow fill:#fdf4ff,stroke:#a21caf,stroke-width:2px;
|
||||
classDef plat fill:#f1f5f9,stroke:#475569,stroke-width:2px;
|
||||
```
|
||||
|
||||
这张图没有现行/远期边界,它是当前认定的产品域间关系。它最该让人看出的是两条**回流虚线**——从成长侧回到创作侧的「创作者继续产出」、从变现侧回到玩家侧的「行为数据回流推荐优化」:正是这两条回流把一条线性的价值链弯成了飞轮,也正是它们对应了商业定位里「数据/网络飞轮」这层护城河(见图 9)。要点出的设计缝是:平台侧被画成「底座」而非链上的一环——它不在主流转线上,而是横向给全链提供 IP、B 端、审核、合规的支撑;这与图 2 把平台侧画成第五大块并不矛盾,图 2 讲的是「它装了哪些域」,本图讲的是「它在流转中扮演底座角色」,两个视角互补。
|
||||
|
||||
### 产品图 7 · 创作者旅程〔Mer新·时·现〕
|
||||
|
||||
这张图从**创作者**的视角,把图 1 闭环的「创作侧 + 成长侧」展开成一条时间线上的旅程:一个创作者从进入平台到看到收益,依次经历哪些步骤、每步落在哪个产品域。它回答的是「一个创作者在这个产品里的一天是怎样的」——这是产品体验的主线之一,也是判断「创作侧的产品设计是否顺畅」的依据。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor C as 创作者
|
||||
participant MAT as 素材中心(MAT)
|
||||
participant CRT as 自定义创作(CRT)
|
||||
participant RT as 实时预览
|
||||
participant PUB as 发布分发(PUB)
|
||||
participant OPS as 数据经营(OPS)
|
||||
|
||||
C->>MAT: 挑素材 / 选玩法模板(可选)
|
||||
C->>CRT: 一句话描述要做什么游戏
|
||||
CRT-->>C: AI 生成可试玩游戏 + 进度实时展示(步骤+百分比)
|
||||
C->>RT: 预览试玩
|
||||
alt 不满意
|
||||
C->>CRT: 带描述迭代 / 一键重新生成
|
||||
CRT-->>C: 重新生成
|
||||
end
|
||||
C->>PUB: 发布前检查(锁风+性能+版权)→ 一键多渠道发布
|
||||
PUB-->>C: 自有必选 + 抖音/微信/快手/TapTap(外部渠道远期)
|
||||
Note over C,OPS: 游戏上线、被玩家刷到、产生收益与行为数据
|
||||
OPS-->>C: 数据看板 / 留存趋势 / 收益明细 → 看到回报
|
||||
```
|
||||
|
||||
这张图把创作者旅程画成「挑素材 → 一句话生成 → 预览迭代 → 发布 → 看收益」五段。最该让人看出的是**两个体验关键点**:一是生成环节的「进度实时展示 + 预览试玩 + 带描述迭代」闭环——这对应 P0 最密集的自定义创作域,它决定创作者第一次用的时候「等得安不安心、改得动改不动」,是留存的第一道关;二是旅程末端的「看到收益」——OPS 数据经营让创作者看到留存、趋势与收益明细,对应成长侧「让创作者留下来」的产品意图,把一次性创作变成可持续经营。要点出的设计缝是:发布环节的**外部渠道(抖音/微信/快手/TapTap)当前是远期**——自有渠道是 MVP 必选且已真端到端,外部渠道在产品口径里是 P1、代码侧基本未建(详见需求映射现状快照);所以图上把外部渠道标为远期,避免让人以为一键多渠道里的每个渠道今天都通了。
|
||||
|
||||
### 产品图 8 · 玩家旅程〔Mer新·时·现〕
|
||||
|
||||
这张图从**玩家**的视角,把图 1 闭环的「玩家侧 + 变现侧」展开成一条旅程:一个玩家从刷到游戏到产生互动与变现,依次经历哪些步骤。它和图 7 是一对——图 7 是「做游戏的人」的主线,图 8 是「玩游戏的人」的主线;两条旅程在「游戏被发布出来、进入信息流」这一点交汇。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor P as 玩家
|
||||
participant FED as 游戏信息流(FED)
|
||||
participant RT as 即点即玩(沙箱运行时)
|
||||
participant SOC as 社区互动(SOC)
|
||||
participant ADV as 广告变现(ADV)
|
||||
participant STU as 同款创作(→工作坊)
|
||||
|
||||
P->>FED: 打开游戏信息流 → 竖屏即刷
|
||||
FED-->>P: 首屏封面(封面/标题/作者/玩法/开始) + 加载进度反馈
|
||||
P->>RT: 点击即玩(无需下载安装)
|
||||
RT-->>P: 即点即玩,上下滑/按钮切换下一款
|
||||
P->>SOC: 点赞 / 收藏 / 分享到社交平台 / 举报
|
||||
Note over P,ADV: 游玩中触发变现
|
||||
ADV-->>P: 激励视频(看 30s 换复活/道具) / 插屏广告
|
||||
opt 玩家被激发想自己做
|
||||
P->>STU: 「发起同款」跳转工作坊 → 变成创作者
|
||||
end
|
||||
```
|
||||
|
||||
这张图把玩家旅程画成「刷 feed → 即点即玩 → 点赞分享 → 发起同款」。最该让人看出的是**两处产品设计的巧思**:一是「即点即玩」——首屏封面给足信息、点击就玩、无需下载安装、上下滑就换下一款,这套竖屏短视频式的体验是绘境区别于「下载-安装-启动」传统小游戏的差异化主战场,对应 P0 最密集的游戏信息流域;二是旅程末端的「**发起同款**」——一个玩家如果被某款游戏激发、想自己做一个,可以一键跳转工作坊变成创作者(P-FED-12)。这一步是整个产品最重要的闭环回路:它把「玩家」转化成「创作者」,让图 7 的创作者旅程与图 8 的玩家旅程**首尾相接**,正是商业定位里「网络效应」护城河(创作者越多→内容越丰富→玩家越多→创作者越多)的产品载体。要点出的设计缝是:广告变现里**真实广告联盟 SDK 当前是待接的**——计费业务逻辑已真(mock 可端到端跑通),但接真实广告联盟受日历闸门(广告资质)约束(详见运营域合规闸门与需求映射现状快照),所以这条变现在产品口径上成立、在落地上还卡着外部资质。
|
||||
|
||||
### 产品图 9 · 商业定位与护城河一图〔SVG新·讲·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「绘境AI 在市场上是谁、靠什么赢」——它把商业定位、竞争格局、资本效率与护城河路径压进一张图,是面向投资人尽调与对外沟通的总览。它也是本图说**最该守诚实纪律**的一张:护城河话术的核心铁律是「**不假装有护城河**——卖的是『不公平起跑 + 飞轮与生态护城河的路径』,任何一处言过其实都会击穿全局信任」;所以图上把「现在真有的」和「要去点燃的」用实心块与紫色虚线框严格分开,绝不让人误以为护城河已经建好。
|
||||
|
||||
图分四层来读。**最上一句话定位**:绘境 = 唯一把「做得出 → 有人玩 → 赚到钱」接成一条闭环的 AI 游戏生态平台,竞品停在生成工具,绘境做全链路——并明确点出「生成是入场券,不是壁垒」。**差异化闭环**那一行把三件事接成链,并在右侧钉死一个最容易被误解的点:护城河真正的来源是数据/网络效应/资产/合规四层,**不是生成引擎**——大模型会追平生成,但追不平这四层沉淀。**中段左侧竞争格局**用三家竞品(极逸 SOON 自研最强但无流量无变现、TapTap 制造有流量但封闭分成低、FunloomAI 有付费验证但品类窄无流量)说明绘境的避战策略:不在技术深度上硬碰,而抢「生态完整度」这条没人占的轴,结论是「技术深度认输,生态完整度抢第一」。**中段右侧资本效率**把「现在真有的不公平起跑」量化——约 1/5 成本、约 1/3 时间、钱撑 18-24 月,策略是「能用成熟开源/商用组合的绝不自研,自研只投在必须自掌的控制点 + 数据入口」。
|
||||
|
||||
整张图最该让人看清的是**底部那一栏的诚实切分**:护城河的四层(数据壁垒 / 网络效应 / 资产壁垒 / 合规壁垒)全部用紫色虚线框 + 「未来式」小标画出,因为它们是**要在窗口期(6-12 个月)里点燃的、而不是已经有的**——短期没有护城河,有的是上面那三样不公平起跑,融资就是点火的燃料钱。这层切分必须看清:如果把飞轮、网络效应、生态资产画成「已有的墙」,就违背了护城河话术的红线。要补充一处源档里的设计缝(图上未展开、读图时一并记住):对外话术与内部判断有一处**刻意的时间差**——护城河话术 B3 对外仍说「复杂引擎用 Cocos / 不自研引擎」,但内部已改判 tier2 富游戏自治轨走 AgentScope(Python 自治 ReAct)+ Phaser/Pixi 全无头引擎、Cocos 收窄到 3D / 复杂场景 / 渠道导出轴(仍是有效决策、非废弃);因为 tier2 还在 0 号 spike 待验,没验证的东西不对外背书,等 spike 过了再同步对外口径。这处「内外口径暂不一致」是有意为之、有据可查,不是漏洞。
|
||||
|
||||
> **产品域图清单与状态表**
|
||||
|
||||
| # | 图名 | 家族 | 形式 | 状态 | 覆盖内容 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 产品闭环全景 | 流 | 引(内联 README §1) | 现 | 做得出→有人玩→赚到钱 闭环主干 + 数据回流;所有产品功能挂靠的主干 |
|
||||
| 2 | 19 个产品域 × 五大块 | 架 | SVG新 | 现 | 创作/玩家/变现/成长/平台 五大块归拢 19 域 + ⭐三 P0 密集域 + 块间流转 + tier2 第二轨边界(虚线·待建) |
|
||||
| 3 | 155 → 55 P0 收敛 | 流 | 引(内联 README §4) | 现 | 155 条完整需求 → 55 条 P0(MVP 验收口径)→ 覆盖全链路闭环;不追功能多、追闭环跑通 |
|
||||
| 4 | 需求编号体系 | 讲 | Mer新(内联) | 现 | `P-{域}-{序号}` + 端/优先级/来源 四属性怎么读;经营≠运营 易错点 |
|
||||
| 5 | 需求 ↔ 模块 M:N 映射(RTM) | ER | SVG新 | 现 | 产品需求(155 P-id) ↔ 技术模块(204 T-id) 多对多矩阵 + 首要owner/★主/辅 读法 + 两块待建映射(虚线·post-spike) |
|
||||
| 6 | 五大块产品域关系 | 架 | Mer新(内联) | 现 | 创作产出→玩家消费→变现回流→创作者留存 的块间流转 + 两条回流虚线(飞轮)+ 平台侧作底座 |
|
||||
| 7 | 创作者旅程 | 时 | Mer新(内联) | 现 | 挑素材→一句话生成→预览迭代→发布→看收益;生成迭代闭环 + 外部渠道远期标注 |
|
||||
| 8 | 玩家旅程 | 时 | Mer新(内联) | 现 | 刷feed→即点即玩→点赞分享→发起同款;即点即玩差异化 + 同款回路接回创作者旅程 + 广告 SDK 待接 |
|
||||
| 9 | 商业定位与护城河一图 | 讲 | SVG新 | 现 | 一句话定位 + 差异化闭环 + 竞争格局 + 资本效率 + 四层护城河(虚线·未来式,诚实不假装有墙)|
|
||||
|
||||
> **状态分布**:九张图整体状态全为 **现**(产品定义层)。其中三处以**元素级虚线**标出 future-state、绝不画成现行 MVP 范围:图 2 / 图 5 的**第二条生成轨(tier2)与治理层**(待 0 号 spike·未落代码·尚无正式 P-id)、图 9 的**四层护城河**(要在窗口期点燃·未来式·非已有)。**产品定义 ≠ 建设进度**:本图说画的是「产品要提供什么」(55 P0 = 验收口径),不是「代码建到哪一步」。55 条 P0 各自的真实完成度(真端到端 / 半真 / 桩)以 `需求模块映射.md` 现状快照与 `docs/mvp/MVP进度总账.md` §2 矩阵为唯一 SoT。**防漂移门**:本文 frontmatter 记产品域五份源档的 commit hash(README @ 366a44b4、需求清单 @ 15b707fd、需求模块映射 @ 7ecd616e、商业定位 @ f4ee2310、护城河话术 @ 5cadf504),源档变更即比对。
|
||||
|
||||
---
|
||||
|
||||
347
docs/architecture/02-架构图说.md
Normal file
347
docs/architecture/02-架构图说.md
Normal file
@ -0,0 +1,347 @@
|
||||
---
|
||||
date: 2026-06-22
|
||||
topic: 架构图说——绘境AI 架构图集(按领域拆分·02)
|
||||
status: 现行为主 · 每图具体映射源档见该图脚注 / 内联小注 · 通用图例见 00-系统总览图说
|
||||
---
|
||||
|
||||
# 02 · 架构图说
|
||||
|
||||
> 本篇是绘境AI **架构图集**的一部分(全 8 篇:[00 系统总览](00-系统总览图说.md) + 01–07 各域)。**通用图例、状态码、按角色读路径见 [00 · 系统总览图说](00-系统总览图说.md)**。
|
||||
> **本域命门(最该据图 review 的设计缝)**:图 11 契约 5 处现实缝;决策史别当现行。
|
||||
|
||||
---
|
||||
|
||||
> **本域讲什么故事**:架构域回答 HOW——这套系统用什么技术、怎么搭。它的十二张图讲清六层分层、那四项最关键选型为什么选 A 不选 B、13 个后端模块各管什么又怎么单向依赖、一条「一句话生成游戏」的请求怎么异步跑通、生成任务状态机怎么管超时 / 失败 / 重试 / 取消、游戏怎么安全跑在玩家面前、推荐打分公式、工程治理(幂等 / SLO / 可观测)、以及那张**最该据图评审的契约族总览**。读完这个域,你知道「这套架构是不是想要的那个、哪里有设计缝」。
|
||||
>
|
||||
> **最该据图 review 的命门缝**:架构域评审的命门在**图 11 契约族总览(声明 vs 现实)**——它不只画理想的「应该怎样」,更如实标出五处已经漂掉的地方:DB 镜像已漂移(contracts 只含 18 个迁移、执行副本有 25 个)、CI 防漂移门缺位(文档写了四道闸、代码里全仓唯一 CI 永不触发)、Dify #6 契约已废、「第 9 契约」五套编号相撞、agent-loop / templates 在 README 目录图漏登。另两处状态纪律:图 2 / 图 3 里被推翻的 Dify / OpenGame / 自研壳是**决策史**(理解「为什么现在是这样」,别误当现行),图 10 的四路可观测落地态是**接**(设计意图真、后端真接上大半还没做)。
|
||||
|
||||
> **本域阅读约定与同步纪律**:本图说不另立设计,只把架构域三份 canonical 设计档画出来——整体分层、关键决策的「为什么」、模块依赖、生成时序、安全运行时、推荐打分出自 `架构/README.md`;13 模块的逐个职责 / 边界 / 依赖 / 建设状态出自 `架构/13模块.md`;契约族导航与口径收口出自 `架构/契约总览.md`。frontmatter 记了这三份的当前 commit hash 作为防漂移门。设计一变动,本图说与对应 SVG 必须同步更新。**本域状态分布**:架构域绝大多数是「现行已建/已实测」,但有两类内容必须看清状态、绝不能画成纯现行——**决策史**(图 2/3 里被推翻的 Dify / OpenGame / 自研壳,是演进对照、不是现行架构)和**契约现实缝**(图 11 里 DB 镜像已漂移、CI 防漂移门缺位等,是声明与代码不符的待决策位)。
|
||||
|
||||
> **本域徽章**(按图点其中几个):**成本**(`#16a34a`):选 Huijing 买现成后台、便宜模型直出、单 key 入计费台账、不硬凑组件。**质量**(`#15803d`):harness 九门兜底、三层约束框架、error_rate 硬降权保可玩底线。**数据**(`#475569`):契约即跨端数据边界、推荐用信号驱动排序、生成成本可对账。**可靠**(`#16a34a`):幂等矩阵、最终一致 + 补偿、SLO + Error Budget、多通道兜底。**可观测**(`#0ea5e9`):四路信号 + SAA 节点 observation——但落地态是「接」,详见运维域。**安全**(`#dc2626`):iframe 沙箱 + CSP 红线、契约防漂移门缺位是真实风险、脱敏。架构域图说里,虚线还额外承担一层**状态语义**:凡是「废·决策史」(图 2/3 被推翻的旧方案)、「待接线」(图 10 可观测落地)、「现实缝」(图 11 已漂移的契约)的元素,一律用虚线框 + 文字小标画出,与「现行已建」的实心块在视觉上一眼区分。
|
||||
|
||||
### 架构图 1 · 六层技术分层〔引·现〕
|
||||
|
||||
这张图回答「整套系统怎么搭起来」。绘境AI 的后端基于 Huijing Cloud(一套基于 Spring Cloud Alibaba 的开源 Java 企业级后台框架,我们 fork 它做二次开发)搭建,在它提供的基座能力之上叠加 13 个游戏业务模块。整套系统自上而下分六层:用户从浏览器进来,经**接入层**(CDN / Nginx)和**网关层**(Spring Cloud Gateway,统一路由 / 限流 / 鉴权 / 灰度),落到**业务服务层**(13 个游戏业务模块);业务服务依赖 Huijing 原生的**基础设施层**(system 用户权限 / infra 文件任务 / bpm 工作流),并向上调用一个独立的 **AI 生成层**来产出游戏(SAA 裸图编排 → new-api 网关 → 便宜 LLM,配 LittleJS + Runner v2 引擎);所有这些都坐在**中间件层**(MySQL / Redis / MinIO)之上,由旁路的**可观测性层**监控。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph ACCESS["接入层 — 把请求接进来"]
|
||||
CDN["CDN<br/>静态资源 / 游戏包加速"]
|
||||
NGINX["Nginx<br/>前端托管 / SSL 终结"]
|
||||
end
|
||||
subgraph FE["前端应用 — 用户看到的界面"]
|
||||
STUDIO["game-studio<br/>Vue3 + Vant<br/>创作者 + 玩家"]
|
||||
ADMIN["game-admin<br/>Vue3 + Element Plus<br/>运营 + 管理员"]
|
||||
end
|
||||
subgraph GW["网关层 — 统一入口"]
|
||||
GATEWAY["Spring Cloud Gateway<br/>路由 / 限流 / 鉴权 / 灰度"]
|
||||
end
|
||||
subgraph BIZ["业务服务层 — 13 个游戏业务模块"]
|
||||
M["studio · project · aigc · runtime · feed<br/>telemetry · pay · trade · community<br/>ip · compliance · biz · ad"]
|
||||
end
|
||||
subgraph INFRA["基础设施层 — Huijing 原生开箱即用"]
|
||||
SYS["system 用户/权限/OAuth2"]
|
||||
INFRASVC["infra 文件/任务/日志"]
|
||||
BPM["bpm 工作流"]
|
||||
end
|
||||
subgraph AI["AI 生成层 — 现行生成主线"]
|
||||
SAA["SAA 裸图编排<br/>Spring AI Alibaba v1.1.2.2"]
|
||||
NEWAPI["new-api 网关<br/>OpenAI 兼容 / 多模型"]
|
||||
LLM["便宜 LLM<br/>DeepSeek / MiniMax"]
|
||||
LJS["LittleJS + Runner v2<br/>Tier1 引擎 / 插件库"]
|
||||
end
|
||||
subgraph MW["中间件层 — 数据与存储"]
|
||||
MYSQL["MySQL 8.0"]
|
||||
REDIS["Redis 7"]
|
||||
MINIO["MinIO / 阿里云 OSS"]
|
||||
FUTURE["Nacos · RocketMQ<br/>(框架自带 · MVP 未部署)"]
|
||||
end
|
||||
subgraph OBS["可观测性层 — 旁路监控"]
|
||||
OBSV["Prometheus · Grafana<br/>Sentry · Jaeger"]
|
||||
end
|
||||
|
||||
NGINX --> STUDIO & ADMIN
|
||||
STUDIO & ADMIN --> GATEWAY
|
||||
GATEWAY --> BIZ
|
||||
BIZ --> INFRA
|
||||
BIZ --> AI
|
||||
AI --> NEWAPI
|
||||
NEWAPI --> LLM
|
||||
BIZ --> MW
|
||||
```
|
||||
|
||||
*(图源:架构/README.md §1)*
|
||||
|
||||
读这张图最该抓住的是它那条贯穿始终的设计取向:**先简后扩、能复用就不自研**。后端复用 Huijing 现成的 60% 后台能力,生成不自研大模型而接通用模型,引擎不自研而用成熟的 LittleJS——这条取向直接决定了系统能用很小的团队和很低的成本跑起来。要注意图里有一处必须按状态读的设计缝:中间件层画了 `Nacos · RocketMQ`,但旁边明写「框架自带 · MVP 未部署」——它们是 Huijing 框架自带的依赖、yaml 也在仓里,但 MVP 运行时并没有启动 broker / registry,凡涉及「异步 MQ」「服务注册发现」的设计在 MVP 阶段都以「进程内调用 / 本地配置」落地。这是 future-state,别当现行已部署。
|
||||
|
||||
### 架构图 2 · 关键选型决策树〔SVG新·讲解·现+史〕
|
||||
|
||||

|
||||
|
||||
这张图回答「架构里那几项最关键的选型,为什么选 A 不选 B」——架构里真正值钱的不是组件清单,而是这些决策背后的理由。图把对整体形态影响最大的四项决策横排,每项给出**现行选定**(绿色实心)、**同期落选候选**(灰框)、以及它击败对方的理由:① 后端框架选 Huijing Cloud(60%+ 后台开箱即用),击败缺企业级基础设施的 NestJS 和缺 RBAC/BPM 现成方案的 Go;② 生成主线分两条线、按品类各选其形:现行的 Tier0/1 廉价线选 new-api 网关 + 便宜 LLM + SAA 裸图(Java)编排(由三次裁定 C2 / HJ-GEN-001 / HJ-AGI-002 逐步锚定),远期的 tier2 富游戏线选 AgentScope(Python 自治 ReAct,独立 service)——一条用确定性图把便宜模型框住、一条放开 agent 自治去啃富交互,两种范式各管各的品类(详见图 3);③ 运行时引擎也随这两条线分轴:Tier0/1 廉价线用 LittleJS 增强发行版(Tier1 唯一交付层),tier2 富游戏自治轨用 Phaser/Pixi 全无头引擎(远期),而 Cocos 收窄到「3D / 复杂场景 / 渠道导出」这一轴(编辑器 + 人在环离线作者),三者击败启动重的 Unity、导出不含快手的 LayaAir——**注意 Cocos 不是被废弃,而是被收窄到它真正适配的那一档,仍是有效决策**;④ AI 素材工具链选 mmx-cli(免 GPU、免训练),ComfyUI 退备选。
|
||||
|
||||
这张图最该让人看清的是底部那条橙色虚线的**决策史带**——也是本图最该守状态纪律的地方。Dify(可视化 LLM 工作流平台)、OpenGame(现成游戏生成 agent)、自研轻量 Canvas Runtime <15KB(自研壳)这三项,在早期蓝图里都是「省自研时间、开箱即用」的首选,但随后的技术验证把它们逐一推翻:Dify+OpenGame 被「直连便宜模型 + 固定运行时更轻就达标」的 spike 证伪、降为远期增强从未部署(对应契约 #6 dify-workflow-io 同步作废);自研壳被 LittleJS 以 85/82 的 spike 比分击败、连 15KB 红线也一并废除(改为三层约束框架)。把它们画出来不是说现在还在用,而是为了理解「为什么现在是这样」——这是据图做架构 review 时最容易踩的坑:把演进中被推翻的旧方案误当现行。所以它们一律虚线框 + 「废·决策史」标,与绿色现行块一眼区分;现行 vs 决策史在生成主线上的更细对照见图 3。
|
||||
|
||||
### 架构图 3 · 生成主线 现行 vs 决策史〔引·流·现+废〕
|
||||
|
||||
这张图把生成主线这一处「演进最剧烈、也最关键」的决策单独放大,讲清现行那条链路到底长什么样、又是怎么从蓝图原案走过来的。**现行主线**(已后端实测)是一条:创作者 Prompt → SAA 裸 `StateGraph` 编排(16 节点 / 7 条件边)→ new-api 网关(OpenAI 兼容、多模型)→ 便宜 LLM(DeepSeek-v4 / MiniMax-M2.7·M3)→ harness 九门兜底(校验 / 构建 / 真玩)→ GamePackage 出包。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph 现行["✅ 现行主线(已实测)"]
|
||||
A1["创作者 Prompt"] --> A2["SAA 裸 StateGraph 编排<br/>16 节点 / 7 条件边"]
|
||||
A2 --> A3["new-api 网关<br/>OpenAI 兼容 · 多模型"]
|
||||
A3 --> A4["便宜 LLM<br/>DeepSeek-v4 / MiniMax-M2.7·M3"]
|
||||
A4 --> A5["harness 九门兜底<br/>校验 / 构建 / 真玩"]
|
||||
A5 --> A6["GamePackage 出包"]
|
||||
end
|
||||
subgraph 决策史["❌ 蓝图原案(从未部署 · 降远期)"]
|
||||
B1["Dify 可视化编排"]
|
||||
B2["OpenGame 生成 agent"]
|
||||
end
|
||||
```
|
||||
|
||||
*(图源:架构/README.md §2.2)*
|
||||
|
||||
几个术语一句话记住:**new-api 网关**让「换模型/多通道兜底」变成网关层的配置事、业务代码无感,且单 key 自动入计费平面(接入坑:baseUrl 要剥掉末尾 `/v1`);**harness 九门**意味着 done 由这些确定性门判定、不让 LLM 给自己打分,门不过就不出包;**SAA 图的唯一布线源**是 `SaaStudioGraph.assemble()`,生产派发与回归测试共用同一份 assemble、避免布线漂移。还有一处范式校正必须看清:这条线的**终态产物定为一份可维护的 `src/` 源项目**(配置驱动 / 模块化 / 资产分离的长生命周期项目,改源不改包、改完重新构建;改数值 / 换美术走确定性编辑免 LLM,改逻辑才让 LLM 重生成对应模块——创始人 2026-06-20 定调)。当前 generate 节点产出的 **gameDefinition 是结构化中间表示、不是合格终态产物**——声明式数据壳把逻辑核塞进 JSON 字符串、运行时用 `new Function` 解释,这只是「通往 `src/` 工程的中间脚手架」、属已知偏离终态的债;产线正把它迁成「直接生成 `src/`」(plan `2026-06-18-001` U1–U4,仍在落地,以生成引擎子树最新裁定为准)。
|
||||
|
||||
这张图要让人看出的设计缝在于「现行」与「决策史」的硬分界:蓝图原案 Dify + OpenGame 那一组(图里 ❌ 标「从未部署·降远期」)和现行 SAA 线之间没有渐变——不是「先用 Dify 后来换 SAA」,而是 Dify/OpenGame 从未部署、直接被验证更轻的路径取代。除此之外还有一条**两条生成线**的边界要一并记住(深度在生成引擎子树展开):现行这条 SAA + LittleJS 廉价线,是为超休闲轻游戏(Tier0/1)量身打造的可靠产线;经营 / 合成 / 多系统富交互那一档富游戏它结构性地够不着,由远期的 **tier2 富游戏自治轨**承载——那条轨换的是整套生成范式(AgentScope Python 自治 ReAct + 独立 service + Phaser/Pixi 引擎 + 三层校验地板 + 人工终审),与廉价线解耦并存、只经公共件交汇。两条线**远期有可能收敛为一条**——把 SAA + LittleJS 也并入 AgentScope 自治范式(登记为未来方向,当前不做、不预先设计)。读这张图时若想看「为什么是 SAA 而不是 Dify」的选型理由,回到图 2 的决策史带;若想看 SAA 16 节点拓扑、加节点方法、救场阶梯、dispatcher 契约、tier2 详设这些更深的实现细节,去生成引擎子文档与 `.agents/skills/saa-graph-orchestration.md`——本图只承载「现行主线轮廓 + 与决策史的边界」,深度留生成引擎子树。
|
||||
|
||||
### 架构图 4 · 13 模块聚类〔引·架·现〕
|
||||
|
||||
这张图回答「13 个后端模块怎么分工」。绘境AI 把全部业务能力按领域边界(一类职责归一处)切成 13 个模块,追求高内聚、低耦合;它们物理上以 jar 聚合进 Huijing 单体一起运行(MVP 单体启动、Spring Profile 控制加载),逻辑上各自独立、可被未来拆分。按在业务闭环里的位置,13 个模块归成四簇:**创作链路**(studio 创作编排 / aigc 无状态生成原子 / runtime 编译沙箱发布 / project 项目生命周期)把游戏做出来;**分发与数据**(feed 游戏流推荐 / telemetry 事件聚合质量评分)让游戏被玩到、被看清;**变现链路**(pay 收单 / trade 分账结算 / ad 广告)把钱赚回来;**平台与合规**(community 社交通知 / ip 素材授权 / compliance 内容安全锁风门 / biz B端定制)让生态转得起来、守得住。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph 创作["创作链路"]
|
||||
STU["studio · 创作编排/编辑器域"]
|
||||
AGC["aigc · 无状态生成原子"]
|
||||
RT["runtime · 编译/沙箱/多渠道发布"]
|
||||
PRJ["project · 项目生命周期 + 专区 Zone"]
|
||||
end
|
||||
subgraph 分发["分发与数据"]
|
||||
FED["feed · 游戏流推荐/互动/分享"]
|
||||
TEL["telemetry · 事件摄取/聚合/质量评分"]
|
||||
end
|
||||
subgraph 变现["变现链路"]
|
||||
PAY["pay · 支付收单/订单/退款对账"]
|
||||
TRD["trade · 分账/结算/钱包/财税"]
|
||||
AD["ad · 广告联盟/植入/曝光计费/归因"]
|
||||
end
|
||||
subgraph 生态["平台与合规"]
|
||||
CMU["community · 社交/互动/排行/通知"]
|
||||
IP["ip · 素材安全/授权链/IP 风格原子"]
|
||||
CMP["compliance · 内容安全/审核/锁风门/RBAC"]
|
||||
BIZ["biz · B/G 端定制工程底座"]
|
||||
end
|
||||
```
|
||||
|
||||
*(图源:架构/README.md §3,与 13模块.md §1 同源)*
|
||||
|
||||
读这张图要记住一条配套口径:图里画的是「应该怎么切」(结构权威),不是「实际建成多少」。每个模块有一个三字母前缀,技术功能用 `T-{模块}-{nn}` 编号(全平台共 204 项,是结构注册表,只增不改号)。**真/桩/未建的实时状态以 `docs/mvp/MVP进度总账.md` 为准,冲突时口径是「状态 > 实现 > 结构」**——例如 ip 模块在结构上独立成簇,实际却是「seam 寄宿在 compliance 里」(有意不独立建),pay 是 Huijing 原生模块但当前未接入单体启动器。这张图给的是空间感和职责边界,看「这块功能落在哪个模块」用它,看「这块建到哪了」要去 13模块.md §4 的状态总表或进度总账。
|
||||
|
||||
### 架构图 5 · 13 模块单向依赖〔引·架·现〕
|
||||
|
||||
这张图回答「模块之间为什么是这个依赖方向」。模块间是单向、低耦合的依赖——A 依赖 B、B 绝不反向依赖 A,且只通过每个模块的 `-api` 包(只声明 DTO + Feign 接口、不含实现)交互。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
STU[studio] --> AGC[aigc]
|
||||
STU --> RT[runtime]
|
||||
STU --> IP[ip]
|
||||
STU --> PRJ[project]
|
||||
STU --> CMP[compliance]
|
||||
AGC --> CMP
|
||||
AGC --> PRJ
|
||||
RT --> PRJ
|
||||
RT --> TEL[telemetry]
|
||||
FED[feed] --> PRJ
|
||||
FED --> TEL
|
||||
TEL --> FED
|
||||
IP --> CMP
|
||||
IP --> TRD[trade]
|
||||
CMP --> AGC
|
||||
CMP --> IP
|
||||
PRJ --> CMP
|
||||
TRD --> PAY[pay]
|
||||
TRD --> AD[ad]
|
||||
AD --> RT
|
||||
BIZ[biz] --> PRJ
|
||||
BIZ --> AGC
|
||||
BIZ --> TRD
|
||||
CMU[community] --> PRJ
|
||||
```
|
||||
|
||||
*(图源:架构/README.md §4,与 13模块.md §2 同源;箭头 A→B 表示 A 依赖 B)*
|
||||
|
||||
读这张图有四条主线:**创作侧 studio 站在最上游**,把活分派给 aigc(生成)、runtime(编译)、ip(素材)、project(落库)、compliance(安全裁决),它自己几乎不被别人依赖——这是「工作台」该有的位置;**生成原子 aigc 保持无状态**,只向下依赖 compliance(Prompt 安全)和 project(写结果),无状态意味着它天然可重放、可横向扩容;**数据回路 telemetry ↔ feed 互相依赖**——这是图里唯一一处双向边(feed 消费质量分来排序、telemetry 回收互动信号来计算),正是平台「越用越聪明」的机制所在;**资金侧 trade 向下收口**,依赖 pay(收单)和 ad(广告收入)拿原始数据,自己只管分账结算。
|
||||
|
||||
这张图最该让人看出的是「为什么单向切分值得」:这种切法让任何一个模块都能独立演进、独立测试,也是未来从单体拆成微服务时的天然切割线——依赖方向就是拆分边界。要注意图里还藏着两处「风格-版权」与「专区」的跨模块协作环路(compliance ↔ ip ↔ aigc),它们不是普通的模块依赖,而是横切关注点,单独由图 12 讲清 owner 与聚合关系,这里只需先记住「telemetry↔feed 那条双向边是有意的、不是设计漏洞」。
|
||||
|
||||
### 架构图 6 · 一条生成请求时序〔引·时·现〕
|
||||
|
||||
这张图回答「把分层、生成主线、模块依赖串起来,一次生成到底怎么跑通」——这是创作链路的核心路径。时序从创作者输入 Prompt + 选风格开始:game-studio 发 `POST /app-api/aigc/generate` 经 Gateway 鉴权转发到 aigc 模块,aigc 创建生成任务(由 `GenerationDispatcher` 派发)后**立即返 202 Accepted + taskId**、前端转去轮询/SSE 监听;真正的生成在后台展开——aigc `dispatch(job)` 进入 SAA 裸图编排,按 render→classify→design→generate 等 16 节点跑,各节点经 new-api 的 OpenAI 兼容接口调模型(单 key 自动入 newapi_cost 计费),模型产出 GameConfig / 游戏代码后过 harness 九门(done 由确定性门定、不过则走修复回环),通过才出 GamePackage、回调写入 project 草稿版本、通知前端任务完成。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as 创作者
|
||||
participant S as game-studio
|
||||
participant GW as Gateway
|
||||
participant AIGC as aigc 模块
|
||||
participant SAA as SAA StateGraph 编排
|
||||
participant NEWAPI as new-api 网关
|
||||
participant LLM as 便宜 LLM
|
||||
participant GATE as harness 九门
|
||||
participant PRJ as project 模块
|
||||
|
||||
C->>S: 输入 Prompt + 选风格
|
||||
S->>GW: POST /app-api/aigc/generate
|
||||
GW->>AIGC: 转发(鉴权通过)
|
||||
AIGC->>AIGC: 创建生成任务(GenerationDispatcher 派发)
|
||||
AIGC-->>S: 202 Accepted {taskId}
|
||||
S->>S: 轮询/SSE 监听任务状态
|
||||
|
||||
AIGC->>SAA: dispatch(job) 进入裸图编排
|
||||
SAA->>SAA: 节点:render→classify→design→generate(16 节点/7 条件边)
|
||||
SAA->>NEWAPI: 各节点经 OpenAI 兼容接口调模型
|
||||
NEWAPI->>LLM: 转发(单 key → 自动入 newapi_cost 计费)
|
||||
LLM-->>NEWAPI: 返回 GameConfig / 游戏代码
|
||||
NEWAPI-->>SAA: 模型产物
|
||||
SAA->>GATE: 校验/构建/真玩九门(done 由确定性门定)
|
||||
GATE-->>SAA: 通过 → 出 GamePackage;不通过 → 修复回环
|
||||
SAA-->>AIGC: 回调 callback:packageUrl + manifest
|
||||
AIGC->>PRJ: 写入草稿版本
|
||||
AIGC-->>S: 任务完成通知
|
||||
```
|
||||
|
||||
*(图源:架构/README.md §5)*
|
||||
|
||||
读这张图要抓住两个关键设计:其一,**生成是异步的**——202 + taskId + 轮询这套,是因为外部模型调用耗时不可控(生成 P50<60s、P95<180s),不能让创作者的请求线程一直挂着;其二,**派发走 `GenerationDispatcher`、生成态藏在 job/callback 契约后**——http worker 与进程内 SAA 图二选一、单写,这层抽象让「现在用进程内 SAA、将来换 http worker」变成可替换的实现细节,调用方无感。这正是图里把 SAA 编排画在 dispatcher 之后的原因:它不是直接被 controller 调,而是被 dispatcher 按契约派发。
|
||||
|
||||
### 架构图 7 · 生成任务状态机〔引·状·现〕
|
||||
|
||||
这张图回答「生成任务自己的生命周期怎么管」。生成任务是一个有明确状态机的对象,它给「超时/失败/重试/取消」都定义了清楚的边:任务创建即 QUEUED,被消费/派发进 RUNNING;RUNNING 有三个出口——生成完成且质量通过 → SUCCEEDED,生成失败或质量不达标 → FAILED,超时(120s)→ TIMED_OUT;FAILED 可重试 ≤2 次回 QUEUED,TIMED_OUT 可重试 ≤1 次回 QUEUED,超过重试次数才终态 FAILED;用户取消则从 QUEUED 或 RUNNING 进 CANCELED。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> QUEUED: 创建任务
|
||||
QUEUED --> RUNNING: 消费/派发
|
||||
RUNNING --> SUCCEEDED: 生成完成 + 质量通过
|
||||
RUNNING --> FAILED: 生成失败 / 质量不达标
|
||||
RUNNING --> TIMED_OUT: 超时(120s)
|
||||
FAILED --> QUEUED: 重试(≤2 次)
|
||||
TIMED_OUT --> QUEUED: 重试(≤1 次)
|
||||
SUCCEEDED --> [*]
|
||||
FAILED --> [*]: 超过重试次数
|
||||
QUEUED --> CANCELED: 用户取消
|
||||
RUNNING --> CANCELED: 用户取消
|
||||
```
|
||||
|
||||
*(图源:架构/README.md §5,紧接时序图后)*
|
||||
|
||||
这张图最该让人看出的,是它把「任何涉及外部模型调用的链路都必须考虑的可靠性设计」具象化了——状态机不是为了好看,而是为了把「模型可能慢、可能失败、可能要让用户取消」这些现实约束变成代码里可执行、可观测的边。配套的硬指标钉在状态机外:生成成功率 ≥80%(MVP 验收线,远期蓝图 ≥85%)、队列最大积压 500 任务、超过返回 429。读这张图时要把它和图 6 配着看:图 6 给「一次成功生成怎么跑」的正路,图 7 给「失败/超时/取消怎么收口」的全路径——正路只是状态机里 QUEUED→RUNNING→SUCCEEDED 那一条主干。
|
||||
|
||||
### 架构图 8 · 游戏安全运行时序〔引·时·现〕
|
||||
|
||||
这张图回答「生成出来的游戏怎么安全地跑在玩家面前」。生成出来的游戏运行在 iframe 沙箱(浏览器内嵌的隔离框架)里,与平台彻底隔离;平台能力靠 WanxiangGameSDK 注入进去——这是平台向游戏注入能力的**唯一通道**,没有它平台就只是个静态文件托管。时序从 game-studio 请求 manifest.json(hash 缓存)开始:拿到 `{entry, assets[], checksum}` 后先校验 manifest 完整性,再并行请求 entry.js + 关键 assets,创建带 CSP + sandbox 的 iframe,注入 GameConfig + Game SDK bridge,沙箱内执行 entry.js 初始化游戏、回 postMessage `game_loaded`,游玩中 SDK bridge 持续上报生命周期事件、结束回报 `game_complete + score`。加载用三容器策略(参考抖音预加载):当前播放的容器之外,前一个在销毁、后一个已预加载完成,上滑切换无缝。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant APP as game-studio
|
||||
participant CDN as CDN/OSS
|
||||
participant SANDBOX as iframe sandbox
|
||||
APP->>CDN: 请求 manifest.json(hash 缓存)
|
||||
CDN-->>APP: {entry, assets[], checksum}
|
||||
APP->>APP: 校验 manifest 完整性
|
||||
APP->>CDN: 并行请求 entry.js + 关键 assets
|
||||
APP->>SANDBOX: 创建 iframe(CSP + sandbox)
|
||||
APP->>SANDBOX: 注入 GameConfig + Game SDK bridge
|
||||
SANDBOX->>SANDBOX: 执行 entry.js → 初始化游戏
|
||||
SANDBOX->>APP: postMessage({type:'game_loaded'})
|
||||
Note over APP,SANDBOX: 游玩中:SDK bridge 上报生命周期事件
|
||||
SANDBOX->>APP: postMessage({type:'game_complete', score})
|
||||
```
|
||||
|
||||
*(图源:架构/README.md §6)*
|
||||
|
||||
这张图最该让人看清的是几条不能破的安全红线——它们是安全与合规可控的根,画在时序之外但比时序更重要:**iframe 沙箱**用 `sandbox="allow-scripts allow-same-origin"`,但有一条 2026-06-10 审计补的红线——`allow-same-origin` 仅当游戏包部署在独立源(与宿主不同源的 usercontent 子域)时才可用,同源下 iframe 能触宿主 DOM/存储甚至自己移除 sandbox,沙箱铁律就失效,所以独立源就绪前禁用 `allow-same-origin`;**CSP** 是 `script-src 'self'; connect-src 'none'`,即游戏内无任何网络请求,且必须经游戏包托管侧的 HTTP 响应头下发、不能只靠 meta 标签;**LLM 产物消毒**——GameConfig 文案字段入库前做白名单字符集 + 长度校验,渲染侧一律转义后绘制,禁 innerHTML/eval。底线原则是:创作者通过配置(不是写代码)驱动游戏行为,平台对运行时代码拥有完全控制权。这套沙箱与「插件↔引擎」受控面是两条正交边界,更深拆解见第四篇产物执行沙箱。
|
||||
|
||||
### 架构图 9 · 推荐打分公式〔SVG新·讲解·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「好游戏怎么被刷到」。MVP 阶段的推荐是规则 + 信号、不上机器学习(那是增长期的事)。每款游戏的曝光排序由一个打分公式决定,图把这个公式拆成三类信号画清楚:**正向信号加分**(quality_score 综合质量分 / freshness 新鲜度 / interaction_rate 互动率,让好游戏浮上来)、**负向信号减分**(skip_rate 跳过率 / error_rate 错误率 / report_rate 举报率,让差游戏沉下去)、**调节项**(bonus_new_creator 新人保底曝光 + bonus_featured 运营精选加分,给生态公平起点和运营调控手)。候选集存在 Redis Sorted Set(TTL 60s,cursor 分页,Sorted Set 天生按分排序适配无限流),由 feed 读取下发成竖屏游戏流。
|
||||
|
||||
这张图最该让人看出的有两点。其一,**error_rate 是唯一的「硬」降权**(图上用红框单标)——加载失败/试玩次数高的游戏直接沉底,因为可玩性是底线,技术上跑不动的游戏一票否决排序,这条把「好不好玩」之前先卡住「能不能玩」。其二,**这套规则为什么够用**:右下角那条飞轮回路画出了「玩家在 feed 玩/互动 → telemetry 回收信号算 quality_score → 回喂 Score 重排候选集」的闭环——质量好 + 爱玩的游戏自然浮上来,数据回流持续校准推荐,这正是平台护城河的来源,不需要 ML 模型在 MVP 阶段就能把排序做对。要按状态读的设计缝在「MVP 现实形态」那个橙虚线框里:候选集**当前可直查 MySQL、Redis 缓存是增长期形态,且游标分页目前是桩(永远返回第一页)**——公式和飞轮是设计真相,但 Redis 候选集与真游标分页的落地仍是增长期的事,别当已全建。
|
||||
|
||||
### 架构图 10 · 工程治理(幂等 / SLO / 可观测)〔SVG新·讲解·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「可靠性和质量怎么被钉死」。这套系统涉及外部模型、异步任务、支付,所以可靠性不是事后补的、而是设计进去的。图把三条贯穿的硬约束并排画出:**① 幂等矩阵**——重复点「生成」靠 idempotency_key(Redis 5 分钟去重)、支付回调重复靠订单状态机 + 乐观锁、发布重复提交靠 project_version 唯一约束,配套原则是尽量避免分布式事务、改用最终一致 + 补偿、并用定时任务扫「中间态超 5 分钟」的记录兜底;**② SLO + Error Budget**——游戏流 API 99.5%(预算 3.6 小时/月)、AI 生成 99%(预算 7.2 小时/月,外部模型不可控故给得宽)、支付 99.9%(预算 43 分钟/月,钱相关最严),整体可用性 ≥99.5%(MVP);**③ 四路可观测**——业务服务把 Metrics/Traces/Logs/Errors 分送 Prometheus/Jaeger/Loki/Sentry,汇到 Grafana。
|
||||
|
||||
读这张图要抓住一个状态分界:**幂等机制与 SLO 目标是现行(写进设计、代码已落),但右侧四路可观测的「落地手段」整体是「接」(待接线)**——图上把四路信号都画成橙虚线 + 「接」小标,只有「SAA 编排节点 observation + new-api 调用埋点」是已就位的实心块,落地状态以运维域观测体系图为准。这是本图最该守的纪律:可观测的「设计意图」是真的,但「后端真接上 Prometheus/Grafana」大半还没做,不能因为 README §9 写了四路就以为监控已建好。图底那条红色风险带也值得记住——它列的不是假想风险而是设计里钉死的应对:**LLM 网关单点通道批量失效**(2026-06 已真实发生:二厂系通道全废,应对是多通道健康巡检 + key 监控 + 降级抽检 + 批跑冻结阀,new-api 网关正是为此设计)、**LLM 成本失控**(应对是限频限额 + 日预算熔断 + 显式 max_tokens)、以及**监管与上游平台风险**(非纯技术,由合规专项承载、登记在此防失踪)。
|
||||
|
||||
### 架构图 11 · 8+2 类契约族总览(声明 vs 现实)〔SVG新·架·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「契约族到底有哪几类、各落哪、各算第几」——也是本域**最该据图做评审**的一张,因为它不只画理想的「应该怎样」,更如实标出已经漂掉的地方。图按三个物理落点组织:**落点① contracts/ 顶层**(跨三仓五工位 SSOT,含跨仓 8 类 + agent-loop/ + templates/)、**落点② game-runtime/src/ 内部接线面**(第 9 类 game-host.d.ts 装载契约 + 第 10 类 runtime-api-2d.d.ts 运行时访问约定,不落 contracts 是因为落了会让跨仓 SSOT 反向 import、拆仓即断)、**落点③ Java 镜像 -api 包**(contracts 的代码镜像,每模块一份,同步序单向:后端先写 -api、前端据此定 TS)。主编号轴只有一条:README 的 1–8 类 + 后来 additive 的第 9/第 10。
|
||||
|
||||
这张图的价值全在底部那条红色的**五处现实缝**带——这是《契约总览》自陈、也是据图 review 最该揪的:**缝① DB 镜像已漂移**(README §41 声称 contracts/db-schemas 是授权源、要求 diff 一致,实情是执行副本 25 个 V*.sql、contracts 只有 18 个、缺 V14–V20,真授权源其实是执行副本那 25 个全集);**缝② CI 防漂移门缺位**(文档把 flyway validate / contracts↔migration diff / prompt 四道闸写成 CI 自动拦截,核到代码:全仓唯一 CI 是 yudao fork 继承件、on push to master 在本仓 dev/2.0.0 永不触发、还跳测、无任何 diff 步——它们是文档承诺不是机器门);**缝③ Dify #6 已废**(dify-workflow-io 对应被推翻的蓝图原案,是 8 类里唯一一个「废」,留 DEPRECATED 墓碑,读到别当现行);**缝④「第 9 契约」五套编号相撞**(跨仓主轴第 9 类装载契约才是真正的第 9,其余「第 9 契约组 9a–9g」「9c」「生成主线 8 契约①–⑧」都是局部上下文,撞数字不撞语义,引用契约要认上下文不认数字);**缝⑤ agent-loop / templates 在 README 目录图漏登**(那张图只画了跨仓 8 类,新人 ls 到这两目录无从对应,本图与《契约总览》补登它们)。把这五处诚实画出来,正是为了让评审者据图就能发现「声明与代码不符」的待决策位——要么补一道真门(wave-close 或 pre-commit 加 contracts↔migration 的 cmp,漂移即拦截),要么裁定执行副本为唯一源、把 contracts/db-schemas 降只读快照,无论哪条都得先让 README §41 的口径和代码实情对上。
|
||||
|
||||
### 架构图 12 · 专区 Zone + 锁风门 Gate〔Mer新·讲解·现〕
|
||||
|
||||
这张图回答「两个跨模块概念的 owner 与聚合关系」。有些能力不属于单一模块,而是横跨多个模块协作完成;为避免「人人都管、结果没人管」的灰色地带,每个横切关注点都指定唯一的 owner(责任主)。MVP 阶段有两个这样的概念,图把它们的 owner、原料供给方、消费方画成一张概念图:**锁风门 Gate**(T-CMP-12,一道「风格-版权一致性」门)owner 是 compliance,它本身不检测风格,而是聚合 aigc 的风格检测原子(T-AGC-19)和 ip 的 IP 风格校验原子(T-IP-04),综合裁决出 pass / review / block,挂在 project 的发布前检查(T-PRJ-05)上;**专区 Zone**(T-PRJ-07,运营双轨分区:授权 IP 区 / UGC 用户原创区)owner 是 project,feed 据它分区推荐(T-FED-15)、ip 据它做素材双轨归类(T-IP-10)、studio 决定创作去向。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph GATE["锁风门 Gate(owner = compliance · T-CMP-12)"]
|
||||
direction TB
|
||||
AGC19["aigc 风格检测原子<br/>T-AGC-19"]:::raw
|
||||
IP04["ip · IP 风格校验原子<br/>T-IP-04"]:::raw
|
||||
CMP12["compliance 聚合裁决<br/>pass / review / block<br/>(标准 / 严格 / 人工复核)"]:::owner
|
||||
PRJ05["project 发布前检查<br/>T-PRJ-05(消费裁决)"]:::consume
|
||||
AGC19 -->|供原料| CMP12
|
||||
IP04 -->|供原料| CMP12
|
||||
CMP12 -->|挂载| PRJ05
|
||||
end
|
||||
subgraph ZONE["专区 Zone(owner = project · T-PRJ-07)"]
|
||||
direction TB
|
||||
PRJ07["project · Zone 实体 / 归属 / 运营位<br/>授权 IP 区 ‖ UGC 区"]:::owner
|
||||
STU["studio<br/>决定创作去向"]:::consume
|
||||
FED15["feed 据 Zone 分区推荐<br/>T-FED-15(双区独立候选)"]:::consume
|
||||
IP10["ip 据 Zone 双轨归类<br/>T-IP-10"]:::consume
|
||||
STU -.->|写入归属| PRJ07
|
||||
PRJ07 -->|分区依据| FED15
|
||||
PRJ07 -->|归类依据| IP10
|
||||
end
|
||||
|
||||
classDef owner fill:#dcfce7,stroke:#16a34a,stroke-width:2px;
|
||||
classDef raw fill:#eff6ff,stroke:#2563eb,stroke-width:1.5px;
|
||||
classDef consume fill:#f1f5f9,stroke:#475569,stroke-width:1.5px;
|
||||
```
|
||||
|
||||
这张图最该让人看出的是「owner 模式怎么消灭灰色地带」:锁风门由 compliance 当 owner(因为它是全平台的内容安全与裁决中枢),但它**不自产**风格检测原子——原料来自 aigc 和 ip,裁决挂到 project,三方各司其职、没有谁越界。这正是图 5 模块依赖里那条 compliance ↔ ip ↔ aigc 环路的真实含义。要按状态读的设计缝有一处:**专区 Zone 在 MVP 阶段还没有独立的数据库实体,是用字段承载的**(有意简化),所以图里 Zone 实体那一格画的是「逻辑归属」、不是一张独立表——这是 project 模块已知的、有意为之的缺口,不是设计漏洞。锁风门则有一处真实的合规债(虽不在本概念图的范围内、但读图时该知道):compliance 的核心检测原子目前全是桩、恒返回 pass,意味着锁风门框架虽真、自动拦截能力还没硬化,这是放量/接广告/上渠道前必须补的。
|
||||
|
||||
> **架构域图清单与状态表**
|
||||
|
||||
| # | 图名 | 家族 | 形式 | 状态 | 覆盖内容 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 六层技术分层 | 架 | 引(内联 README §1) | 现 | 接入→网关→业务→基座→AI→中间件 + 旁路可观测;先简后扩取向;Nacos/RocketMQ = future-state 未部署 |
|
||||
| 2 | 关键选型决策树 | 讲 | SVG新 | **现+史** | 框架(Huijing)/生成两线(廉价 new-api+SAA ‖ tier2 AgentScope)/引擎分轴(LittleJS ‖ Phaser/Pixi ‖ Cocos 收窄 3D+渠道导出)/素材(mmx-cli) 四选定击败谁;废弃候选 Dify/OpenGame/自研壳作决策史;Cocos=收窄非废弃 |
|
||||
| 3 | 生成主线 现行 vs 决策史 | 流 | 引(内联 README §2.2) | **现+废** | 现行 SAA+LittleJS 廉价线 16 节点链路 vs 蓝图原案 Dify/OpenGame;终态产物=src 源项目(gameDefinition JSON 为中间脚手架·迁移中);两条生成线边界 + tier2 远期可能收敛入 AgentScope |
|
||||
| 4 | 13 模块聚类 | 架 | 引(内联 README §3) | 现 | 四簇 13 模块 + T-id 注册表;结构权威 vs「状态>实现>结构」口径 |
|
||||
| 5 | 13 模块单向依赖 | 架 | 引(内联 README §4) | 现 | 单向 -api 依赖四主线;telemetry↔feed 唯一双向边;依赖方向=未来微服务切割线 |
|
||||
| 6 | 一条生成请求时序 | 时 | 引(内联 README §5) | 现 | 202+taskId 异步派发 + SAA 编排 + 九门 + 回调写库;dispatcher 契约可替换 |
|
||||
| 7 | 生成任务状态机 | 状 | 引(内联 README §5) | 现 | QUEUED→RUNNING→SUCCEEDED/FAILED/TIMED_OUT + 重试/取消;成功率≥80%/积压500/429 |
|
||||
| 8 | 游戏安全运行时序 | 时 | 引(内联 README §6) | 现 | manifest 校验→iframe+CSP→注入 SDK→三容器;allow-same-origin/CSP/产物消毒三红线 |
|
||||
| 9 | 推荐打分公式 | 讲 | SVG新 | 现 | Score 正负信号加权 + 调节项 + Redis 候选集;error_rate 硬降权;飞轮回路;候选集/游标桩现实形态 |
|
||||
| 10 | 工程治理(幂等/SLO/可观测) | 讲 | SVG新 | 现 | 幂等矩阵 + 三服务 SLO/Error Budget + 四路可观测(落地态=接)+ 三关键技术风险及应对 |
|
||||
| 11 | 8+2 类契约族总览 | 架 | SVG新 | 现 | 三落点 + 主编号轴;诚实标出 5 缝:DB 漂移/CI 门缺位/Dify#6 废/第9契约五套相撞/agent-loop+templates 漏登 |
|
||||
| 12 | 专区 Zone + 锁风门 Gate | 讲 | Mer新(内联) | 现 | 两横切概念 owner 与聚合:Gate=compliance 聚合 AGC19+IP04 挂 PRJ05;Zone=project owner;Zone 无独立实体(字段承载) |
|
||||
|
||||
> **状态分布**:现 ×10、现+史 ×1(图 2,决策史对照)、现+废 ×1(图 3,含废弃蓝图)。**注**:图 2/3 的「史/废」指其中**并列的决策史/废弃候选**部分(Dify/OpenGame/自研壳),现行选定部分仍是「现」;图 9/10/11 虽整体「现」,但各含一处必须按状态读的缝(候选集桩 / 可观测落地=接 / 5 处契约现实缝),已在散文与图内标清。**防漂移门**:本文 frontmatter 记架构域三份源档的 commit hash(README/契约总览 @ 38357c3d、13模块 @ 7ecd616e),源档变更即比对。
|
||||
|
||||
---
|
||||
|
||||
172
docs/architecture/03-产物执行沙箱图说.md
Normal file
172
docs/architecture/03-产物执行沙箱图说.md
Normal file
@ -0,0 +1,172 @@
|
||||
---
|
||||
date: 2026-06-22
|
||||
topic: 产物执行沙箱图说——绘境AI 架构图集(按领域拆分·03)
|
||||
status: 现行为主 · 每图具体映射源档见该图脚注 / 内联小注 · 通用图例见 00-系统总览图说
|
||||
---
|
||||
|
||||
# 03 · 产物执行沙箱图说
|
||||
|
||||
> 本篇是绘境AI **架构图集**的一部分(全 8 篇:[00 系统总览](00-系统总览图说.md) + 01–07 各域)。**通用图例、状态码、按角色读路径见 [00 · 系统总览图说](00-系统总览图说.md)**。
|
||||
> **本域命门(最该据图 review 的设计缝)**:别把机制已建当已安全;两条正交边界别混。
|
||||
|
||||
---
|
||||
|
||||
> **本域讲什么故事**:沙箱回答一个被独立成档的硬问题——**一款 AI 生成的不可信游戏代码,怎么在玩家浏览器里被隔离着安全跑起来**。生成主线已从「禁代码、填参数」迁到「让 agent 写码」,注入面就是模型现写的 JavaScript 本体,平台必须把每一款生成游戏当成有恶意、有 bug 的不可信输入。它的七张图讲清三层封堵(build 段静态扫描 / iframe + CSP / sandbox 属性)、取包 sha256 校验注入时序、postMessage 双向桥双校验、SDK 受控能力面、两条正交边界、CSP / 同源红线 / 产物消毒、三容器加载 / 失败 / 销毁态机。读完这个域,你知道「这套隔离方案是不是想要的那个」。
|
||||
>
|
||||
> **最该据图 review 的命门缝**:沙箱域评审最该守的纪律点是「**别把机制已建当成已经安全**」——iframe、桥、双校验、sha256 这套都真跑通过了,但它现在跑在同源过渡态,HJ-AUDIT-001 那条「独立源就绪前禁用 allow-same-origin」的红线在代码里并未强制,origin 白名单还含字符串 'null'。还有两条最该看清的概念边界:**两条信任边界正交、别混**(沙箱边界 = iframe 壳 vs 宿主、受控面 = 游戏代码 vs 引擎,受控面在沙箱里面、沙箱在受控面外面,破一条另一条仍兜);以及 **'unsafe-eval' 看着危险但风险被纵深防御承接住了、不是漏洞**(逻辑串先经 build 段静态扫描、再加 connect-src 'none' 无出网、再加 iframe sandbox 隔离)。
|
||||
|
||||
> **本域阅读约定与同步纪律**:本图说不另立设计,只把架构域里 `产物执行沙箱.md` 这一份 canonical 设计档画出来。frontmatter 记了它的当前 commit hash 作为防漂移门。设计一变动,本图说与对应 SVG 必须同步更新。**本域状态分布**:这套机制(iframe + 桥 + 双校验 + sha256)**已全部建成、真跑通过**,所以七张图的整图状态都是**现**。但「机制建成不等于合规收口」——源档 §8 逐条带 file:line 记了四处真实债(CSP 文档口径与代码对不上、sandbox 属性三处不一致、后端下发的 sandboxAttr 前端没接线、HJ-AUDIT-001 同源红线当前是过渡态)。这些**现状债**不是「待建」,而是「现行机制里的已知缺口」,图上一律用**橙色虚线框 + 文字小标**与「现行已建的实心块」一眼区分开。
|
||||
|
||||
> **本域徽章**(主要关心其中两个):**安全**(`#dc2626`):这是本域的主轴。三层封堵(build 段静态门 / iframe CSP / sandbox 属性)、桥的 origin + schema 双校验、storage 四道闸、sha256 取包完整性、bundle 内联前的 `</script>` 消毒——全是为了把不可信代码关在笼子里。**质量**(`#15803d`):受控面那条「异常绝不向游戏抛、超时就降级、写类 fire-and-forget」的降级铁律,根源是玩家验收门五条 AND 里的「无错」——游戏运行期一旦抛未捕获错误就判不过,所以受控面任何意外都得自己吞掉。本域图说最该守的纪律点是:**别把「机制已建」当成「已经安全」**。读图时凡见橙色虚线框,就是「这里还有债、别当已合规」。
|
||||
|
||||
### 沙箱图 1 · 不可信代码隔离全景〔SVG新·架·现〕
|
||||
|
||||

|
||||
|
||||
这张全景图回答整份文档的总问题:**一段模型现写的不可信 JavaScript,凭什么敢放进玩家的浏览器里跑**。答案是三层封堵,它们在不同时机、不同位置生效,合起来才是完整的封锁,单看任何一层都不够。图从左到右按「出厂前 → iframe 这层壳 → iframe 外的宿主平台」铺开,用绿色标出唯一被放行的通道、用红色虚线标出每一个被封死的逃逸面。
|
||||
|
||||
最左边一层最容易被忽略,因为它**不在 runtime、而在 build 段**。`build-from-source.mjs` 的 `scanLogic` 在把 gameDefinition 装配成可玩工厂、交给 esbuild 打包**之前**,对模型产出的 `behavior.code` 和 `rule.condition` 做静态扫描,命中危险模式就转成 `validationError` 回灌给 repair,而不是指望 prompt 自觉。为什么这一层必须放在 build 边界做?因为同步 JS 在进程内没法被硬中断——一个 `while(true)` 死循环或一次沙箱逃逸只要执行了就晚了,所以唯一的机会是在执行前的校验边界把危险模式拦掉。图上把 `LOGIC_BANS`(逃逸 / DOM 网络 / 死循环 / 确定性四类)和 `CONDITION_BANS`(条件必须是无副作用的纯布尔表达式)的实际拦截清单都列了出来,让人看清这层拦的不是抽象的「危险代码」,而是一份具体的黑名单。
|
||||
|
||||
中间是 iframe 这层壳,它叠了两道:**CSP** 硬编码进 srcdoc 的 `<meta>`,其中 `connect-src 'none'` 是最关键的一条——它禁掉一切网络出站,所以即便游戏代码想把玩家数据 `fetch` 出去也发不出去;引擎 bundle 不在 iframe 内 fetch,而是由宿主层 fetch 后内联进来,所以这条不会卡死引擎装载。**sandbox 属性**则封死宿主 DOM 逃逸、顶层导航与弹窗,并把游戏与宿主之间的通道收窄到只剩 postMessage 一条。这条收窄直接决定了产品形态:广告、支付、存储这些要碰平台资源的事,游戏在 iframe 内根本办不了(没网络、碰不到宿主 DOM),只能经 postMessage 抛给宿主侧去办、办完再回包——这就是为什么 SDK 的 ad/pay/storage 都是「游戏发请求 → 宿主执行 → 回包」的形状,而不是游戏直接调。
|
||||
|
||||
这张图必须让人看出的「设计缝」画在右下角那个橙色虚线框里:**机制建成 ≠ 合规收口**。当前整套跑在同源过渡态(同源 srcdoc 配 `allow-same-origin`),HJ-AUDIT-001 的同源红线在代码里没强制;CSP 的文档口径写的是 `script-src 'self'`、代码实为 `'unsafe-inline' 'unsafe-eval'`;sandbox 属性在 DB 默认值、前端硬编码、文档示例三处不一致;后端下发的 `sandboxAttr` 前端压根没消费。这四条债的收敛要一起做(迁独立 usercontent 子域、CSP 改 HTTP 响应头下发、sandboxAttr 真接线)才闭合,详见图 2 注记与源档 §8。把这块诚实画出来,正是为了不让人看到「三层都建了」就以为已经安全了。
|
||||
|
||||
### 沙箱图 2 · 取包 → sha256 校验 → iframe + CSP → 注入 时序〔SVG新·时·现〕
|
||||
|
||||

|
||||
|
||||
这张时序图把一款不可信游戏「从后端取包到在玩家面前可玩」的全过程展开成六条泳道之间的一串动作。它的叙事主线是:**每一环都假设上一环的产物可能有问题**,所以取包之后必有完整性校验、注入之时必带 CSP、建桥之后所有消息必过双校验。
|
||||
|
||||
取包这一步并不是一条直线,而是 `resolvePackage` 分四态走,图上方用橙色虚线框列了出来:创作者预览时 `props.manifest` 直接传一个内存里的包进来、不走网络;玩家试玩时按 `versionId` 取运行包清单、清单里带 `manifestUrl` 就去拉真包做 sha256 校验;清单没有 `manifestUrl`(mock 阶段后端还没回填)就退 demo 兜底;取包或校验中途出任何错,也退 demo 兜底。这里有一个关键且有意的设计:可恢复的失败**只 `console.warn`、不向上 emit error**。原因是父级 `Play` 把 error 当致命态处理、会用 `v-else-if` 把宿主整个隐藏掉显示「加载失败」,而 demo 兜底本可以正常试玩,两者冲突,所以宁可降级也不上抛。
|
||||
|
||||
中段是这张图的安全支点——**sha256 双通道校验**(图中绿色块)。manifest 从后端拉下来后要确认传输途中没被篡改、和后端写包时算的 checksum 一致。校验走双通道:安全上下文(https / localhost)优先用原生 `SubtleCrypto`,性能最好;非安全上下文回退一份纯 JS 的 SHA-256 完整实现。为什么需要这份纯 JS 回退?因为创始人用局域网 IP 明文 http(例如 `http://100.64.0.7:4173`)跨内网机访问时,浏览器判定为「非安全上下文」、`crypto.subtle` 直接是 `undefined`,旧实现这时会抛错、导致校验失败退 demo 兜底,最终页面误报「游戏加载失败 / 网络波动」——真因是上下文不安全,根本不是网络。回退纯 JS 后,完整性校验在明文 IP http 和安全上下文下行为一致。后端这一端也对齐了字节一致性:取 manifest 的端点返回的是原始 JSON 文本(返回类型 `String`,`GlobalResponseBodyHandler` 只拦 `CommonResult` 不拦它),保证前后端对同一份字节算摘要。
|
||||
|
||||
后段是注入与回流。`buildIframeSrcdoc` 用一个不常见的手法叫「函数序列化注入」:`createWanxiangSDK` 和 `startRuntime` 都是不依赖模块外部符号的纯工厂函数,用 `Function.prototype.toString()` 取源码文本拼进 iframe 内联 `<script>` 重新求值——这样同一份 TS 源既被宿主工程类型检查、又在 iframe 内真跑,不用为它们单独配打包产物。引擎 bundle 则作一个独立内联 `<script>` 注入、暴露契约冻结的全局名 `window.__GameBundle`,并经 `escapeBundleForInlineScript` 断掉 `</script>` 变体防止它越出脚本块。最后一条回流值得记住:**游戏没有自己的 emit 通道发 game_end**,所以宿主 `watchGameEnd` 每 500ms 轮询 `host.state().phase`、到 `gameover` 就 latch 一个 `game_end` 代发——这是过渡口径,ref 游戏是纯引擎工厂、内部没 SDK,自发不出终态,等 W-G1 生成主线落地后改由各品类标准信号产出、这个轮询桩可下线。图右侧旁注还点出加载超时按装载路分流(引擎包 12s、旧 demo 路 5s),因为引擎冷启动是旧路的 4.8~5.3 倍、内联 bundle 解析会逼近甚至超过 5s,放宽到 12s 是为了防误杀,而首屏 P75<3s 由 `perf_first_screen` 单独监测、与这个防挂死上界正交。
|
||||
|
||||
### 沙箱图 3 · postMessage 双向桥与双校验〔Mer新·时·现〕
|
||||
|
||||
下面这张流程图把桥(`bridge.ts` 的 `HostBridge` 类)处理一条 iframe 来消息的判定过程画清楚。桥的设计立场是:**把 iframe 来的每一条消息都当不可信边界处理**——先过 origin 闸、再过 schema 闸,任一不过就丢弃、绝不分发;过了两道闸还要分辨它是不是宿主先前请求的回包,是回包就消费掉、不是才往上分发。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
M["iframe postMessage 来一条消息"] --> O{"① origin 在白名单?<br/>isOriginAllowed"}
|
||||
O -->|"否(空白名单默认拒绝)"| R1["onReject('origin_not_allowed')<br/>丢弃"]:::deny
|
||||
O -->|是| S{"② schema 逐字段校验?<br/>validateEnvelope"}
|
||||
S -->|否| R2["onReject(reason)<br/>丢弃"]:::deny
|
||||
S -->|是| P{"是宿主请求的回包?<br/>requestId 配对命中 pending"}
|
||||
P -->|是| RP["消费 pending 回调<br/>clearTimeout + resolve"]:::ok
|
||||
P -->|否| D["onMessage 分发给上层 GamePlayer"]:::ok
|
||||
|
||||
classDef deny fill:#fee2e2,stroke:#dc2626,stroke-width:2px;
|
||||
classDef ok fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px;
|
||||
```
|
||||
|
||||
第一道是 **origin 白名单**:`isOriginAllowed` 对空白名单**默认拒绝**——白名单为空视为不允许任何来源,这是安全默认而非疏忽。因为 srcdoc 文档的 origin 是 `null`,建桥时 `buildOriginAllowlist` 在 `includeNull` 时会把字符串 `'null'` 连同宿主自身 origin 一起加进白名单(这也正是 §8 同源债的一个落点:过渡态下白名单含 `'null'`)。第二道是 **schema 逐字段校验** `validateEnvelope`:`channel` 必须严格等于固定标识 `wanxiang-game-sdk`(否则是噪声或伪造),`type` 必须在 8 个枚举的 `VALID_TYPES` 内(即图 4 那张 type 表的全集),`direction` 必须合法,`traceId` 必须是字符串(贯穿链路必备),`payload` 必须存在,`requestId` 若带则必须是字符串。这里有个有意的细节:`validateEnvelope` **不抛异常、只返回判定结果**——源码注释写得明白,「异常本身也是一种攻击面」,所以校验器自己绝不制造可抛路径。
|
||||
|
||||
过了两道闸之后的回包识别,是为了支撑「请求-响应」语义:宿主往游戏发消息用 `post`(`targetOrigin` 用 `'*'`,因为 srcdoc 的 origin 是 `null` 没法精确指定),而 `request` 是 Promise 化的请求-响应、带 5s 超时(`REQUEST_TIMEOUT_MS`),**超时就以 `undefined` 兜底 resolve、绝不 reject**——向上抛 reject 会打断游戏,所以宁可降级。卸载时 `dispose` 移监听、清所有挂起请求的定时器防泄漏。这张图没有现行/远期边界,它就是现行桥的真实判定流;要注意的「设计缝」只有一处,且不在桥本身而在它的输入侧——白名单含 `'null'` 是同源过渡态的产物,独立源落地后这一项会随 §8 收敛一起收紧。
|
||||
|
||||
### 沙箱图 4 · 受控面(SDK bridge)能力面〔SVG新·类·现〕
|
||||
|
||||

|
||||
|
||||
这张类图回答「平台到底向不可信游戏注入了什么能力、又是怎么注入的」。结论是:iframe 内的游戏只能经一个全局对象 `window.WanxiangGameSDK`(加上引擎装载契约)与外界打交道,受控面之外一律被 CSP 和 sandbox 封死——没有这个 SDK,平台就只是个静态文件托管。图把受控面拆成 Core 层和 Plugin 层,并把另一条并列的入口(引擎装载契约)单列在右栏。
|
||||
|
||||
**Core 层内联进游戏入口、压缩后小于 8KB、首屏即在**,暴露 `init` / `on` / `track` / `reportError` / `ad` / `pay`。`init` 注入 `traceId` 贯穿「生成 → 运行 → 上报」全链路;`track` 是 10 条 / 5s 的批量缓冲、写类 fire-and-forget;`ad` / `pay` 经桥的 `request` 走 5s 超时降级。**Plugin 层按需懒加载、首屏不付代价**,其中 storage 这个面尤其要小心,因为它直接写宿主的真 localStorage——图上把它的四道闸列全了:闸①只放行恰好等于 `idle:gameId:versionId` 的 key(tycoon 这类无离线态的模板根本不发 storage、白名单也不含它的前缀),闸②挡 4KB 以上的 value(idle 存档实际不到 200B),闸③在写入前用 `JSON.parse` 校验、回读时只接受对象形态(防有人手工篡改 localStorage 注入脏数据),闸④落盘时加 `wxgame:` 前缀做命名空间隔离。这里有个设计点值得点出:回包给游戏的是宿主侧**已经解析好的对象**、不是原始字符串,解析在宿主这道受信边界做、runtime 侧零 `JSON.parse`,守住「游戏代码不引可抛路径」的红线。
|
||||
|
||||
整张图最该让人记住的是那条贯穿所有受控面的**降级铁律**:异常绝不向游戏抛、超时就降级、写类操作 fire-and-forget。它的根源不是工程洁癖,而是玩家验收门那五条 AND 里的「无错」——游戏运行期一旦抛出未捕获错误就判不过,所以受控面任何意外都得自己吞掉。右栏的引擎装载契约(`window.__GameBundle.bootGameHost` / `render(mainContext)` / `ctx.getEngine()`)是**与 SDK 并列的第二条受控入口**,但它属于另一条正交边界(详见图 5),图上特意提醒:软著 `ruanzhu-5` 和专利 `01-受控插件引擎` 写的是这条受控插件面、不是 iframe 产物沙箱,引用时别张冠李戴。图下方的 8 种 postMessage type 表是桥 schema 闸的枚举全集,把每个 type 的方向和用途列清,让人对照图 3 看清「双校验放行的到底是哪 8 类消息」。
|
||||
|
||||
### 沙箱图 5 · 两条正交边界(别混)〔SVG新·架·现〕
|
||||
|
||||

|
||||
|
||||
这张图专治一个最容易混的概念:系统里有**两条信任边界**,它们方向正交、位置嵌套,必须分清。边界① 是**沙箱边界**——「整个 iframe 这层壳」与「外面的宿主平台」之间的隔离,它活在 iframe 壳本身,是本档(产物执行沙箱.md)的主轴;边界② 是**受控面**——iframe 内部、「游戏代码」与「引擎能力」之间的约束(`api.d.ts` 的 `PluginContext`),它管「游戏代码调引擎时只能走公开 API」,是 `引擎与运行时.md` 的主轴。一句话记牢:**受控面在沙箱里面,沙箱在受控面外面。**
|
||||
|
||||
图用嵌套的方框把这个关系画成可视:红色虚线大框是沙箱壳、紫色虚线框嵌在里面是受控面、最内层才是不可信游戏代码——它被两层边界一起关着。右上角的「同心嵌套示意」是这张关系的速记版。之所以强调它们「正交」,是因为两条边界各管一段、不互为替代、缺一不可,而且任何一条被破时另一条仍在兜:如果沙箱边界破了(比如同源过渡态 `allow-same-origin` 下游戏触到了宿主 DOM),受控面拦不住它——这正是 §8 同源债的要害;反过来如果受控面破了(游戏绕开公开 API 去抓引擎内部),外层沙箱壳仍兜得住,不致让数据外泄或出网。把这层「破了一条还有另一条」的纵深关系画出来,就能解释为什么两条边界都不能省。
|
||||
|
||||
这张图右下角把「最容易混的三处」钉死,都是实际踩过或容易踩的坑:一是引用知识产权时别张冠李戴(软著/专利写的是受控插件面=边界②,不是 iframe 产物沙箱=边界①);二是关联档分工别串(`引擎与运行时.md` 讲装载 + 引擎能力=边界②,本档讲执行隔离 + 安全边界=边界①,两者正交不重叠);三是收敛各管各的(沙箱债 §8 的同源/CSP/sandboxAttr 属边界①,受控面的血统债 random/time/input 属边界②,别合并谈)。这张图没有现行/远期边界,它讲的是一个**当前就成立的概念结构**;它和图 1 的关系是图 1 给「三层封堵的全景」、图 5 给「两条边界的嵌套关系」,一个讲手段、一个讲概念分层。
|
||||
|
||||
### 沙箱图 6 · CSP / 同源红线 / 产物消毒〔Mer新·讲·现〕
|
||||
|
||||
下面这张讲解图把沙箱里「与外界资源打交道」最硬的三条红线集中起来:CSP 的 `connect-src 'none'`、HJ-AUDIT-001 的 `allow-same-origin` 同源红线、以及 bundle 内联前的产物消毒。它们分别管「不准出网」「同源下不准用 same-origin」「注入的脚本不准越界」,是沙箱安全性的三块基石,也是 §8 现状债集中的地方。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph CSP["① CSP(硬编码进 srcdoc <meta>)"]
|
||||
direction TB
|
||||
C1["default-src 'none' —— 兜底封掉一切未显式放开的资源类型"]
|
||||
C2["connect-src 'none' —— 禁一切网络出站(最关键)<br/>引擎 bundle 由宿主层 fetch 后内联,不在 iframe 内 fetch,故不被卡"]
|
||||
C3["script-src 'unsafe-inline' 'unsafe-eval'<br/>gamedef 运行时用 new Function 编译逻辑串,必需 'unsafe-eval'"]:::debt
|
||||
end
|
||||
subgraph SO["② 同源红线 HJ-AUDIT-001(当前=过渡态)"]
|
||||
direction TB
|
||||
O1["红线:allow-same-origin 只有当游戏包托管在独立源<br/>(usercontent 子域·与宿主不同源)时才可用"]
|
||||
O2["现状债:现行同源 srcdoc + allow-same-origin,红线代码里未强制<br/>origin 白名单还含字符串 'null'"]:::debt
|
||||
end
|
||||
subgraph SAN["③ 产物消毒"]
|
||||
direction TB
|
||||
N1["escapeBundleForInlineScript:断 </script>(含大小写/空白变体)和 <!--<br/>让 bundle 文本无法越出 <script> 边界"]
|
||||
N2["纵深防御:bundle 来自后端 engineBundle、整包 sha256 已覆盖完整性<br/>消毒是额外一层、不是唯一依赖"]
|
||||
end
|
||||
DEF["纵深承接:'unsafe-eval' 的风险由三重边界一起兜——<br/>逻辑串先经 build 段 scanLogic 静态拦危险面 + connect-src 'none' 无出网 + iframe sandbox 隔离"]:::ok
|
||||
C3 --> DEF
|
||||
O2 --> FIX["收敛方向(三件一起做才闭合):<br/>① 迁独立 usercontent 子域(让 allow-same-origin 真安全)<br/>② CSP 从 srcdoc meta 改 HTTP 响应头下发<br/>③ sandboxAttr 这条 DB→VO→前端链真接线"]:::fix
|
||||
|
||||
classDef debt fill:#fff7ed,stroke:#d97706,stroke-width:1.5px,stroke-dasharray:5 4;
|
||||
classDef ok fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px;
|
||||
classDef fix fill:#eff6ff,stroke:#2563eb,stroke-width:1.5px;
|
||||
```
|
||||
|
||||
读这张图要抓住一个反复出现的张力:**`'unsafe-eval'` 看着危险,但它是 gamedef 运行时必需的、且风险被纵深防御承接住了**。声明式 gameDefinition 的 behaviors / rules 各带逻辑 JS 串,`gd-runtime.js` 用 `new Function` 编译执行,缺 `'unsafe-eval'` 会抛 `EvalError` 被静默吞进 errors[]、tickBehaviors 空转、游戏只渲首帧静态、世界永不演进(这是 2026-06-21 实证过的 bug:加上之后 errCnt 从 7 降到 0、score 从 0 开始演进)。它的风险承接是一条纵深链:逻辑串先在 build 边界经 `scanLogic` 静态拦掉危险面,再加 `connect-src 'none'` 断网络出站,再加 iframe sandbox 隔离——三重边界使它不扩大真实攻击面。所以图上把 `'unsafe-eval'` 标成债色、但用一条绿线指向「纵深承接」,表达「它是有意的、不是漏洞」。这里也要诚实记一笔文档漂移:`.agents/rules/security-and-reliability.md` §1.1、skills 手册、契约注释都写 `script-src 'self'`,但代码实为 `'unsafe-inline' 'unsafe-eval'`、且硬编码在 srcdoc meta 里,**以代码为准、文档口径已过期**。
|
||||
|
||||
第二块同源红线是本域最该警惕的过渡态。HJ-AUDIT-001 说 `allow-same-origin` 只有当游戏包托管在独立源时才能用,因为同源下 iframe 能触宿主 DOM / 存储、甚至自己移除 sandbox,沙箱铁律就失效了;但代码现状是同源 srcdoc 配 `allow-same-origin`、origin 白名单还含 `'null'`,红线在代码里没强制。这是已知的、独立源落地前的过渡态,不是已合规。图把它和收敛方向连在一起,强调三件事(迁独立 usercontent 子域、CSP 改 HTTP 响应头下发、sandboxAttr 真接线)必须一起做才闭合——只做一件不解决问题。第三块产物消毒相对干净:`escapeBundleForInlineScript` 断 `</script>` 和 `<!--` 防 bundle 越出脚本块,而且 bundle 来自后端、整包 sha256 已覆盖完整性,消毒只是纵深里额外的一层、不是唯一依赖。
|
||||
|
||||
### 沙箱图 7 · 三容器加载 / 失败 / 销毁态机〔Mer新·状·现〕
|
||||
|
||||
下面这张状态图回答 feed 里「上下滑动切游戏」时,沙箱容器的生命周期怎么管。绘境AI 的 feed 是短视频式的游戏流,玩家上下滑会连续切换游戏,所以沙箱容器不是一个、而是逻辑上的三个角色在轮转:**当前正在播放的、前一个正在销毁的、后一个正在预加载的**。这张图把这三态的流转、以及「加载失败怎么降级」画清楚。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
direction LR
|
||||
[*] --> Preload : 进入可视区前预取
|
||||
Preload : 后一个 · 预加载
|
||||
Preload : 取包 + sha256 校验 + buildIframeSrcdoc<br/>iframe 挂载但未掌帧
|
||||
Current : 当前 · 播放中
|
||||
Current : boot 掌帧 · game_loaded→phase=ready<br/>game_start · watchGameEnd 轮询终态
|
||||
Disposing : 前一个 · 销毁中
|
||||
Disposing : dispose 移监听 + 清挂起请求定时器<br/>iframe 卸载 · 防泄漏
|
||||
|
||||
Preload --> Current : 滑到它(成为当前)
|
||||
Current --> Disposing : 滑走(被下一个取代)
|
||||
Disposing --> [*] : 释放完成
|
||||
|
||||
Current --> Fallback : 加载失败 / sha256 不过 / 超时
|
||||
Fallback : 降级 demo 兜底<br/>只 console.warn · 不向上 emit error
|
||||
Fallback --> Disposing : 滑走时照常销毁
|
||||
|
||||
note right of Current
|
||||
加载超时按装载路分流:
|
||||
引擎包 12s · 旧 demo 路 5s
|
||||
(引擎冷启动 4.8~5.3×)
|
||||
end note
|
||||
```
|
||||
|
||||
读这张图要抓住两个设计点。其一,**三容器轮转是为了让「即点即玩」成立**:如果每次滑到一款游戏才开始取包、校验、注入、冷启动引擎,玩家会看到明显的等待;提前在「进入可视区之前」就把后一个容器预加载好(取包 + sha256 + 挂载 iframe、但还不掌帧),滑到时才 `boot` 掌帧,等待就被藏进了滑动的过程里。与此对称,前一个滑走的容器进入销毁态,`dispose` 必须移监听、清掉所有挂起请求的定时器——这一步不能省,否则切几十款游戏后会积累一堆未清理的监听和定时器、内存泄漏。其二,**加载失败是一条降级支路、不是终止**:sha256 校验不过、取包出错、或加载超时,都不让宿主整个隐藏显示「加载失败」,而是降级到 demo 兜底、只 `console.warn`、不向上 emit error(原因同图 2——父级 `Play` 把 error 当致命态会隐藏宿主,而 demo 本可正常试玩)。这条降级支路汇回正常的销毁流:滑走时它照常被 `dispose`。
|
||||
|
||||
这张图没有现行/远期边界,它是现行 feed 容器生命周期的真实形态;唯一的过渡口径在「终态怎么来」——`watchGameEnd` 轮询 `host.state().phase` 到 `gameover` 才 latch 一个 `game_end` 代发,是因为 ref 游戏自己没有 emit 通道,等 W-G1 落地后改由各品类标准信号产出、轮询桩可下线(与图 2 同源)。
|
||||
|
||||
> **产物执行沙箱图清单与状态表**
|
||||
|
||||
| # | 图名 | 家族 | 形式 | 状态 | 覆盖内容 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 不可信代码隔离全景 | 架 | SVG新 | 现 | 三层封堵(build 段 scanLogic / iframe CSP / sandbox 属性)+ 唯一放行通道 postMessage + 封死逃逸面 + 同源过渡态四债(§8)诚实标注 |
|
||||
| 2 | 取包 → sha256 校验 → iframe + CSP → 注入 时序 | 时 | SVG新 | 现 | resolvePackage 四态 + sha256 双通道(Web Crypto / 纯 JS 回退)+ 字节一致性 + 函数序列化注入 + __GameBundle + 加载超时分流 + game_end latch 代发 |
|
||||
| 3 | postMessage 双向桥与双校验 | 时 | Mer新(内联) | 现 | origin 闸(空白名单默认拒绝·含 'null')+ schema 逐字段闸 + 回包 requestId 配对 + request 5s 超时降级不 reject + 校验不抛异常 |
|
||||
| 4 | 受控面(SDK bridge)能力面 | 类 | SVG新 | 现 | Core 层 <8KB(init/on/track/reportError/ad/pay)+ Plugin 层懒加载(storage 四闸)+ 引擎装载契约(第二条入口)+ 降级铁律 + 8 type 表 |
|
||||
| 5 | 两条正交边界 | 架 | SVG新 | 现 | 沙箱边界(iframe 壳 vs 宿主,边界①)vs 受控面(游戏↔引擎,边界②)嵌套关系 + 破一条另一条仍兜 + IP/关联档/收敛三处别混 |
|
||||
| 6 | CSP / 同源红线 / 产物消毒 | 讲 | Mer新(内联) | 现 | connect-src 'none' + 'unsafe-eval' 纵深承接(漂移①以代码为准)+ allow-same-origin 同源红线过渡态(HJ-AUDIT-001)+ escapeBundle 消毒 + 收敛三件一起做 |
|
||||
| 7 | 三容器加载 / 失败 / 销毁态机 | 状 | Mer新(内联) | 现 | 当前播放 / 前一销毁 / 后一预加载 三态轮转 + dispose 防泄漏 + 加载失败降级 demo(不上抛)+ 加载超时分流 + game_end latch 过渡口径 |
|
||||
|
||||
> **状态分布**:现 ×7(机制全建成、真跑通过)。本域无「待接 / 待建 / 缓做 / future」整图——但**现行机制内有四处已知债**(CSP 文档口径漂移、sandbox 属性三处不一致、sandboxAttr 半孤儿、HJ-AUDIT-001 同源红线过渡态),在图 1 / 图 6 中用橙色虚线框 + 文字小标与「现行已建实心块」区分,绝不画成「已合规收口」。**防漂移门**:本文 frontmatter 记源档 `产物执行沙箱.md @ 38357c3d`(随 7fff6518 总图说提交锚定),源档变更即比对。**单源说明**:本域所有图均为新作(SVG新 / Mer新),无「引」类;源设计档 `产物执行沙箱.md` 自身在 §1/§2/§3 内嵌了三段 Mermaid(端到端时序、三重边界、桥双校验),本图说不复制它们——图 2 是把 §1 时序升保真为 SVG、图 3 的桥流程按「桥判定流」单独框选重画、图 1/4/5 则是源档没有的新视角(全景 / 类图 / 边界嵌套)。
|
||||
|
||||
---
|
||||
|
||||
223
docs/architecture/04-后端图说.md
Normal file
223
docs/architecture/04-后端图说.md
Normal file
@ -0,0 +1,223 @@
|
||||
---
|
||||
date: 2026-06-22
|
||||
topic: 后端图说——绘境AI 架构图集(按领域拆分·04)
|
||||
status: 现行为主 · 每图具体映射源档见该图脚注 / 内联小注 · 通用图例见 00-系统总览图说
|
||||
---
|
||||
|
||||
# 04 · 后端图说
|
||||
|
||||
> 本篇是绘境AI **架构图集**的一部分(全 8 篇:[00 系统总览](00-系统总览图说.md) + 01–07 各域)。**通用图例、状态码、按角色读路径见 [00 · 系统总览图说](00-系统总览图说.md)**。
|
||||
> **本域命门(最该据图 review 的设计缝)**:DB 镜像漂移;桩与真分清;全图无物理外键。
|
||||
|
||||
---
|
||||
|
||||
> **本域讲什么故事**:后端域回答服务实现视角的几件事——13 个业务模块在工程上怎么摆(两段式 -api / -server、包名自动套端前缀、错误码分段)、全平台数据长什么样、怎么跨域连、以及「谁能做什么」这条鉴权约束在代码里如何强制。它的八张图里,图 5 是**全仓唯一的 ER 权威**(据 Flyway V1–V25 真实落库的约 40 张表画出五条业务链),图 6 是五条业务链路的跨模块调用,图 7 是鉴权双模型。读完这个域,你知道「这套后端结构是不是想要的那个」。
|
||||
>
|
||||
> **最该据图 review 的命门缝**:后端域八张图整体都是「现」(已落代码、已 e2e 验证),但现行结构里仍有几处桩与缝必须照实看清——图 5 的 **contracts DB 镜像已漂移**(只读 contracts 会漏掉 aigc 的 level/trace 列、source_project 的并发幂等唯一键、feed 的 exposure_limit)、图 6 的 **compliance 检测原子恒返回 pass / feed 游标分页是桩 / 真广告联盟 SDK 是桩**(这些缺口的共同特点是逻辑已建、卡在不可压缩的日历闸门或 W-G1 质量门)、图 7 的**网关双重校验是未来态而非现状**。还有一条贯穿全域的设计意图最该让评审看出:**全图无物理外键**(归属靠 Service 可信边界的 eq 谓词、不靠 DB 约束),以及源(game_source_project)与产物(game_version)两个存储面解耦——「改源不改包」范式在数据层的落点。
|
||||
|
||||
> **本域阅读约定与同步纪律**:本图说不另立设计,只把后端域四份 canonical 设计档画出来——工程落地(分层、两段式、端前缀、错误码、单体形态)出自 `后端/README.md`,全平台数据模型出自 `数据模型.md`,鉴权与权限出自 `鉴权与权限.md`,模块边界与业务链路另引架构域的 `13模块.md`。frontmatter 记了这四份的当前 commit hash 作为防漂移门。设计一变动,本图说与对应 SVG 必须同步更新。**本域状态分布**:后端域八张图**全部是「现」(现行已建)**——它们画的都是已落代码、已 e2e 验证过的工程结构与数据形态,不存在「设计已出待接线」或「远期目标态」的图。但「现行已建的结构」里仍有几处**设计缝与桩**必须照实标出:contracts 的 DB 镜像已漂移、compliance 检测原子恒返回 pass、feed 游标分页是桩、网关双重校验是未来态而非现状——这些图上都用文字或虚线如实点出,绝不因为整体是「现」就把桩画成真。
|
||||
|
||||
> **本域徽章**(主要关心其中三个):**数据**(`#475569`):跨表软关联而非物理外键、两个 quality_score 口径不互灌、play_count 三处口径只有一处权威、金额一律 BIGINT 以分计——这是图 5 / 图 6 的主轴。**安全**(`#dc2626`):权限只在后端可信边界强制、B 端 RBAC 与 C 端归属隔离两套并存、创作白名单必须在后端、mock 后门生产关死——这是图 7 / 图 8 的主轴。**可靠**(`#16a34a`):幂等键四范式、资金守恒不变式、统一发布编排的跨表原子事务、契约与实现解耦让模块独立演进。后端域图说里,**虚线主要承担「软关联」与「异步回灌」两层语义**:图 5 的跨表连线全是逻辑软关联(代码里一根物理外键都没有),用虚线画;图 6 的飞轮回路是异步回灌,用绿虚线画,与同步主调的实线区分开。红色虚线框另外标「越界红线」。
|
||||
|
||||
### 后端图 1 · 后端分层与依赖(实现视角)〔引·现〕
|
||||
|
||||
这张图回答「后端是什么形状」。它把后端的实现视角浓缩成三层:最下面是 **Huijing fork 提供的基座**(system 用户/权限/OAuth2、infra 文件/任务/日志、bpm 工作流,以及 pay——pay 是 Huijing 原生模块,MVP 阶段还没接入这套单体),中间是 **13 个 game 业务模块**(本域主体),每个模块再拆成 **-api / -server 两段式**工程结构。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph HJ["Huijing fork — 基座(开箱即用,不属于业务)"]
|
||||
SYS["system<br/>用户 / 权限 / OAuth2"]
|
||||
INFRA["infra<br/>文件 / 任务 / 日志"]
|
||||
BPM["bpm 工作流"]
|
||||
PAYN["pay(huijing 原生)<br/>当前未接入单体"]
|
||||
end
|
||||
subgraph BIZ["13 个 game 业务模块 — 本域主体"]
|
||||
direction LR
|
||||
STU["studio 创作编排"]
|
||||
AGC["aigc 生成原子"]
|
||||
RT["runtime 编译/发布"]
|
||||
PRJ["project 生命周期"]
|
||||
FED["feed 游戏流"]
|
||||
TEL["telemetry 遥测"]
|
||||
TRD["trade 分账结算"]
|
||||
CMU["community 社区"]
|
||||
IP["ip 素材/授权<br/>(seam 寄宿 compliance)"]
|
||||
CMP["compliance 安全/审核"]
|
||||
BIZM["biz B端定制"]
|
||||
AD["ad 广告"]
|
||||
end
|
||||
subgraph PKG["每个模块的两段式工程结构"]
|
||||
API["-api 包<br/>枚举 / 错误码段 / 跨模块 DTO·Feign"]
|
||||
SRV["-server 包<br/>controller / service / dal / convert"]
|
||||
end
|
||||
BIZ --> HJ
|
||||
STU --> PKG
|
||||
AGC --> PKG
|
||||
RT --> PKG
|
||||
note["全部以 jar 聚合进 huijing-server 单体运行<br/>包名统一 com.wanxiang.huijing.game.module.{模块}.{层}"]
|
||||
PKG -.-> note
|
||||
```
|
||||
|
||||
*(图源:后端/README.md §1)*
|
||||
|
||||
读这张图要抓住两个后端实现上的特殊归属,README 在图注里专门点了出来:其一,**pay 单独画在基座里**,因为它是 Huijing 原生模块、当前未接入单体;其二,**ip 不独立建模块,而是作为一条 seam(接缝/横切能力)寄宿在 compliance 里**。这两点不是疏漏,是有意的工程取舍,后面图 5 的数据视角会再次印证——库里确实没有独立的 `game_pay_*` / `game_ip_*` 迁移落地。
|
||||
|
||||
这张图的边界声明很清晰:后端域只回答「模块在工程上怎么实现(HOW)」,**不回答「每个模块各管什么领域、彼此怎么依赖(WHAT)」——那是架构域的职责**,在第三篇 13 模块图里。两者各守一摊、互不重复,这样无论改架构还是改代码,都只有一处需要更新。所以这张图刻意薄;要看 13 模块各自的职责边界与依赖方向,去架构篇,本图说不重画一份会过期的副本。
|
||||
|
||||
### 后端图 2 · 两段式模块:-api 契约面 / -server 实现面〔SVG新·类·现〕
|
||||
|
||||

|
||||
|
||||
这张图把图 1 里「每个模块的两段式工程结构」放大讲清。它回答的是后端低耦合到底靠什么落地——答案是一道很硬的边界:**每个 game 模块都拆成 `-api` 和 `-server` 两个 Maven 子模块,跨模块只准依赖对方的 `-api`,绝不许直接碰 `-server`**。
|
||||
|
||||
图左半边是单个模块的剖面(以 project 为范例,所有模块同构)。`-api` 是契约面,只声明、不实现:里面放枚举(状态机取值、业务常量)、错误码常量(本模块独占段,见图 4)、跨模块 DTO(模块间传输对象)、以及 Feign 接口或 `@Primary` 本地 bean(远程调用声明——单体内同进程直调,拆微服务才换真 Feign)。`-server` 是实现面,放真正干活的代码:controller(app/admin 双端)、service(业务逻辑、`@Transactional` 只加这层、归属校验在此强制)、dal(DO + Mapper)、convert(DO↔VO↔DTO 转换)。
|
||||
|
||||
图右半边讲清这道边界为什么值钱。当 studio 这样的上游要调 project / aigc / runtime 时,**它的 pom 只声明依赖各模块的 -api,编译期就根本拿不到对方的实现类**——越界在构建期就被挡死,而不是靠人自觉。好处是任一模块都能独立演进、独立测试,后续从单体拆成独立仓时不被实现耦合绊住:契约稳定、实现可换。图里特意用红色虚线框标出「这些模块各自的 -server 对 studio 不可见」,强调依赖图里**根本不存在**指向 -server 的边——这条红线画出来是为了让人一眼记住禁止什么。
|
||||
|
||||
要补充三个工程上的硬约束,图右侧也钉住了:DTO/VO/DO 三层语义不可混用(DTO 在 -api 跨模块共享、VO 在 -server controller 面向前端、DO 在 -server dal 映射表,错位会出问题);契约不放后端(API/DB/SDK/event 等 8 类跨端契约的单一事实源是仓根的 `contracts/`,后端只引用、不另立,DB schema 的 Flyway 执行副本要和 contracts 源 diff 一致);双包同名 controller 必须显式 bean 名(`controller.admin` 与 `controller.app` 下同简单类名的控制器,裸 `@RestController` 会 bean 名相撞、整个 context 启动失败,这是踩过两次的坑)。物理形态上,13 模块是逻辑划分,**全部以 jar 聚合进 huijing-server 单体进程运行**,Nacos/RocketMQ 是框架自带的远期形态、MVP 未部署。
|
||||
|
||||
### 后端图 3 · 包名 → 端前缀自动生效〔Mer新·流·现〕
|
||||
|
||||
这张图讲一个很容易被当成「魔法」的机制:app 控制器和 admin 控制器的代码里**都不写 `/app-api`、`/admin-api` 前缀**,但请求进来却能各自落到对的端上。它的原理不是魔法,而是 Huijing 框架按**包路径通配**:控制器放在 `controller.app.*` 包下,框架自动给它套 `/app-api` 前缀;放在 `controller.admin.*` 包下,套 `/admin-api`。这条规则的前提,正是图 2 里那条统一包名约定——所有业务代码都在 `com.wanxiang.huijing.game.module.{模块}.{层}` 之下,框架才能据此通配。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
DEV["控制器源码<br/>@RequestMapping('/project')<br/>(不写端前缀)"]:::src
|
||||
subgraph SCAN["Huijing 框架按包路径通配"]
|
||||
direction TB
|
||||
APP{"包在<br/>controller.app.*<br/>之下?"}
|
||||
ADM{"包在<br/>controller.admin.*<br/>之下?"}
|
||||
end
|
||||
DEV --> APP
|
||||
DEV --> ADM
|
||||
APP -->|是| PAPP["自动套 /app-api<br/>→ /app-api/project"]:::app
|
||||
ADM -->|是| PADM["自动套 /admin-api<br/>→ /admin-api/project"]:::adm
|
||||
PAPP --> UT1["URL 前缀反推 userType<br/>/app-api → MEMBER (C 端)"]:::note
|
||||
PADM --> UT2["URL 前缀反推 userType<br/>/admin-api → ADMIN (B 端)"]:::note
|
||||
|
||||
classDef src fill:#eff6ff,stroke:#2563eb,stroke-width:2px;
|
||||
classDef app fill:#f5f3ff,stroke:#7c3aed,stroke-width:1.5px;
|
||||
classDef adm fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px;
|
||||
classDef note fill:#f1f5f9,stroke:#475569,stroke-width:1.2px;
|
||||
```
|
||||
|
||||
这张图最该让人看出的,是它和鉴权的衔接——**端前缀不只是路由,还反推用户类型**。框架据 URL 前缀实时推导 userType:`/app-api` 推出 MEMBER(C 端创作者+玩家),`/admin-api` 推出 ADMIN(B 端运营+管理员)。userType 不在登录时记死、而是按前缀实时算,这正是图 7 鉴权双模型的入口:一个 C 端 token 去打 `/admin-api`,会因为「token 携带的 userType 与 URL 推导出的不一致」在 TokenAuthenticationFilter 那一步就被拒。所以这张看似只讲路由的图,其实是鉴权链路的第一段。它没有现行/远期的灰度,就是当前真相。
|
||||
|
||||
### 后端图 4 · 错误码分段:各模块独占一段〔Mer新·讲·现〕
|
||||
|
||||
这张图回答「全平台的错误码怎么不打架」。规则很简单:错误码格式是 `1-{模块段}-{业务}-{细分}`,**每个模块独占一段、互不重叠**,新增模块在自己 `-api` 的错误码常量类里登记自己那一段。这样任意两个模块各自演进、各自加错误码,都不会撞号。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
FMT["错误码格式:1-{模块段}-{业务}-{细分}<br/>各模块独占一段,禁止冲突"]:::fmt
|
||||
subgraph BASE["Huijing 基座段(源档明确给出)"]
|
||||
direction LR
|
||||
B1["1-001 system"]
|
||||
B2["1-002 infra"]
|
||||
end
|
||||
subgraph GAME["13 game 业务模块段"]
|
||||
direction LR
|
||||
G1["1-100 project"]
|
||||
G2["1-101 aigc"]
|
||||
G3["1-102 runtime"]
|
||||
G4["1-103 feed"]
|
||||
G5["1-104 telemetry"]
|
||||
end
|
||||
subgraph INFER["顺延分配(源档未逐一给出·按『每模块一段顺延』推断)"]
|
||||
direction LR
|
||||
I1["1-105 pay"]
|
||||
I2["1-106 trade"]
|
||||
I3["1-107 community"]
|
||||
I4["1-108 ip"]
|
||||
I5["1-109 compliance"]
|
||||
I6["1-110 biz"]
|
||||
I7["1-111 ad"]
|
||||
end
|
||||
FMT --> BASE
|
||||
FMT --> GAME
|
||||
FMT --> INFER
|
||||
|
||||
classDef fmt fill:#fefce8,stroke:#ca8a04,stroke-width:2px;
|
||||
```
|
||||
|
||||
读这张图要注意一处诚实标注:**源档只明确给出了 system / infra / project / aigc / runtime / feed 六段**(图上前两组),其余模块(pay/trade/community/ip/compliance/biz/ad)的段号是**按「每模块一段顺延」规则推断分配的**(图上第三组单独框出、标「顺延·推断」),不是源档逐一写死的。这处推断照实标,是为了不把推论当成已核实的事实——真要给某模块定错误码段,以该模块 `-api` 的错误码常量类登记的为准。举两个图 7 会再次出现的真实锚点:project 的归属守卫抛 `PROJECT_NOT_OWNER(1_100_000_001)`,落在 project 的 100 段;创作白名单拒绝抛 `PLAYER_CREATE_NOT_IN_WHITELIST(1_002_090_003)`,落在 passport 寄宿的 system/infra 段——这也印证了 passport 身份层物理上寄宿在基座、不在 13 模块清单里这件事。
|
||||
|
||||
### 后端图 5 · 全平台数据模型跨域 ER(canonical)〔SVG新·ER·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「全平台的数据长什么样、怎么跨域连」——也是**全仓唯一的 ER 权威**,其它图说(如本主档别处、运维篇)要画数据都引用它、不另起一份。它据 Flyway V1–V25 真实落库的约 40 张表画出来,按五条业务链分块:① 创作链路(studio+aigc+project+source)、② 编译发布与合规闸门(runtime+compliance)、③ 分发与数据回路(feed+telemetry)、④ 钱财闭环(ad+trade)、⑤ 身份关联(community+biz),最上面一条是所有创作的归属起点 passport 身份层。
|
||||
|
||||
这张图最该先记住的是图顶那条**全图铁律**:所有连线都是逻辑「软关联」,**代码里一根物理外键都没有**。这是单体内有意的解耦——模块之间只经各自的 `-api` 包用 DTO 软关联,归属隔离靠 Service 的可信边界(Mapper 强制带 `eq(userId)` 谓词),而不是靠 DB 约束。代价是数据一致性要 Service 自己保,收益是模块能各自演进、后续拆独立仓时不被外键绊住。所有 `game_*` 表里的 `creator_user_id` / `user_id`,数值上都等于 `game_player.id`(OAuth2 的 userId),但代码层一根外键都没有。图上因此用实线画主干强关系、虚线画软关联与回灌,二者一眼区分。
|
||||
|
||||
图右下角用三个框钉住了三处**最容易误读的真相**,读图时务必一并记住。第一处是**必须知道的数据语义坑**(踩错会出真 bug):两个 quality_score 不能互灌(aigc 的是 0–1 衡量生成质量、telemetry/feed 的是 0–100 衡量运营质量);play_count 有三处口径但只有一处权威(试玩会话不计、telemetry 聚合才是权威源、project 的是回灌的物化字段);金额一律 BIGINT 以「分」计、禁浮点;业务归属列 `creator_user_id` 与审计列 `creator` 是两回事。第二处是**contracts 镜像已漂移**——执行权威是 huijing-server 里的 25 个迁移 V1–V25,但 contracts/db-schemas/ 只含 18 个(单模块 additive 的 V14–V20 不进 contracts),**只读 contracts 会漏掉** aigc 的 level/trace/source/modify 列、source_project 的并发幂等唯一键、feed 的 exposure_limit。这是个真实的漂移面,图上诚实画出、不掩盖。第三处是**两套身份数值与代码路径都分开**:C 端玩家创作者用 `game_player`(物理寄宿 huijing-module-system、不在 13 模块清单),B 端管理员用 `system_users`;而 pay/ip 当前没有独立迁移落地,赋余额走 trade 的 grant、素材登记走 studio 的 `game_material`——这和图 1 的「pay 未接单体、ip 寄宿 compliance」从数据侧对上了。
|
||||
|
||||
还有一个贯穿全图、最该让评审看出的设计意图是**源与产物两个存储面解耦**:`game_source_project` 存源(source_json)、`game_version` 存产物(package_url 指向的包),「改源不改包」指的是改了源要重新构建才生成新产物、不是直接动包;源构建失败时会留下孤儿源(status=2)而不污染产物面。这正是生成主线「游戏是长生命周期项目、改源重建」范式在数据层的落点。迁移只增不改——新增表或列要回 `数据模型.md` 补节点,逐列细节以迁移头注为准。
|
||||
|
||||
### 后端图 6 · 五条业务链路(跨模块调用)〔SVG新·时·现〕
|
||||
|
||||

|
||||
|
||||
如果说图 5 是数据的静态结构,这张图就是它的动态——把「一句话到能赚钱」拆成**五条链**,看每条链怎么跨模块串起调用。五条链分别是:链 1 创作(一句话→可试玩草稿)、链 2 发布(草稿→已发布入流)、链 3 试玩(刷流→取包→沙箱跑→互动)、链 4 广告收益(曝光/激励→计费→分账→入钱包)、链 5 数据回路(遥测→聚合→质量分→feed 重排)。每条链左侧标该步的主调模块,实线是同步主调、绿虚线是异步回灌。
|
||||
|
||||
读这张图要抓住几条最该看出的设计意图。**链 2 发布是全仓唯一一处真正的跨表原子发布**:project 的统一发布编排把 compliance 裁决、runtime 出包、feed 入流串成一个事务,任一步失败就整体回滚、不留半截状态——这是脊柱级的可靠性能力,图上用事务边界框单独强调。**链 5 数据回路里 telemetry ↔ feed 是 13 模块里唯一一处双向依赖**:feed 消费 telemetry 算出的质量分来排序,telemetry 回收 feed 上的互动信号来计算,这条唯一的双向边正是平台「越用越聪明」飞轮的机制所在,图上用一条绕回的绿虚线画出来。**链 4 广告收益的两段靠 source_ref 对账锚点串起**:ad 的 `revenue.id` 就是 trade 的 `income.source_ref`,trace_id 从 ad 一路透传到 trade 串起对账链,金额全程 BIGINT 以分计——这条边界不容含糊,是钱的事。
|
||||
|
||||
这张图也照实标出了几处**设计缝与桩**(用 📌 标在对应步骤上),绝不把桩画成真:链 3 的游标分页目前是桩(永远返回第一页)、`packageUrl` 字段恒为 null(真实取包要走 `GET /runtime/package/{vid}`);链 4 的真广告联盟 SDK 是桩、被 mock 挡在审核闸门前;compliance 的检测原子目前也是桩。这些缺口的共同特点是**逻辑已建、卡在不可压缩的日历闸门**(ICP 备案、支付进件、广告审核)或 W-G1 质量门,而不是代码没写——策略是先把逻辑建好、闸门到位即接。最后一个衔接点:这五条链正是运维冒烟门验的五条端到端闭环(见运维篇图 4),冒烟门按链分组点检每条链的关键 API 是否都在岗。
|
||||
|
||||
### 后端图 7 · 鉴权 OAuth2 / RBAC 双模型〔SVG新·类·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「谁能做什么」。它要先记住图顶那条**铁律**:权限只在后端可信边界强制,前端拦截一律不算数;当前 MVP 是单体,可信边界就是服务侧那一个点(不是网关)。权限基座是 Huijing fork 自带的 Spring Security + OAuth2 + RBAC,全仓没有引入 sa-token。
|
||||
|
||||
这张图的核心是**两类用户、两套权限模型并存**,这是它最该让人看清的一件事。系统只有两类用户:MEMBER(C 端,创作者+玩家同型)和 ADMIN(B 端,运营+管理员),userType 按 URL 前缀实时推导(接图 3)。一个请求穿过服务侧 TokenAuthenticationFilter(取 token 换登录态、校验 userType 与端前缀一致)和 URL 准入后,按端类型分流到两套截然不同的强制机理:
|
||||
|
||||
- **B 端走声明式 RBAC**(图左):后台所有 admin 控制器统一用 `@PreAuthorize("@ss.hasPermission('模块:资源:动作')")` 声明所需权限位,真正的裁决在 `PermissionServiceImpl` 按「角色→角色拥有的菜单」求交集,超管短路、严格模式(权限点找不到 Menu 即判无权限),落在 RoleDO/MenuDO/RoleMenuDO/UserRoleDO 四张表上。强制点是方法级的注解。
|
||||
- **C 端走 Service 层归属隔离**(图右,黄金范式):app 控制器**完全不用 `@PreAuthorize`**——这是此前文档最大的认知缺口。它的范式是控制器取 `getLoginUserId()` 透传给 Service,Service/Mapper 用 `eq(creatorUserId/userId)` 把当前用户钉进 WHERE 谓词,从数据层强制只能碰本人数据。落地靠一个黄金归属守卫 `validateProjectOwner`(不是本人就抛 `PROJECT_NOT_OWNER`「无权操作他人的游戏项目」),后续 C 端写域直接克隆它。强制点是数据层的谓词,不是角色权限。
|
||||
|
||||
图底还叠了一层**创作白名单**(A2 内测准入):C 端虽创作者与玩家同型,但「能不能创作」由 `validateCreator` 卡住,`creator_flag≠1` 就拒。这道白名单最该记住的是——**前端守卫挡不住直连 API,所以它必须在后端强制**。图右下角的「现状 vs 未来态」是这张图的纠偏点:控制器注释里多处写的「网关+服务端双重校验」是**微服务拆分后才成立的未来态**,当前单体下网关根本不在请求路径上、权限强制 100% 在服务侧单点;图上用实心绿块画现状、虚线框画未来态,把这处与现状不符的旧说法如实标清。mock 后门是 staging 现状、生产必须关死的红线,它和 `validateCreator` 查无行放行是配套的内测豁免。这张图配合图 8 一起看:图 7 讲两套强制机理,图 8 讲哪些端点落哪一档。
|
||||
|
||||
### 后端图 8 · 匿名 / 登录态的准入矩阵〔Mer新·讲·现〕
|
||||
|
||||
这张图把图 7 的两套机理落到「具体端点该走哪一档」的速查上。平台的端点按准入要求分四档:匿名公开读、登录态、B 端 RBAC 权限位、C 端归属隔离。匿名读端点用 `@PermitAll` 由框架扫描注解自动转成免登 URL 列表,其余端点落到 `anyRequest().authenticated()` 的兜底(未登录即 401)。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
REQ["请求到达服务侧"] --> Q1{"端点带<br/>@PermitAll?"}
|
||||
Q1 -->|是| ANON["① 匿名公开读<br/>任何人无需 token<br/>(app 端共 34 处匿名读)"]:::anon
|
||||
Q1 -->|否| Q2{"已登录?<br/>(userType 须匹配端前缀)"}
|
||||
Q2 -->|否| E401["401 未登录"]:::deny
|
||||
Q2 -->|是| Q3{"端类型?"}
|
||||
Q3 -->|"/admin-api · B 端"| RBAC["③ RBAC 权限位<br/>@PreAuthorize + PermissionServiceImpl<br/>持对应角色-菜单权限的 ADMIN"]:::rbac
|
||||
Q3 -->|"/app-api · C 端"| OWN["④ 归属隔离<br/>Service eq(userId) + validateProjectOwner<br/>MEMBER 且是数据归属人"]:::own
|
||||
RBAC -->|无权| E403["403 无权限"]:::deny
|
||||
OWN -->|非本人| E403
|
||||
|
||||
ANON -.->|"匿名读三纪律"| RULE["只暴露公开字段·裁剪 PII<br/>公开读靠手动 eq 谓词隔离(不假定 DataPermission 自动生效)<br/>跨租户读显式收敛"]:::rule
|
||||
|
||||
classDef anon fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px;
|
||||
classDef rbac fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px;
|
||||
classDef own fill:#ede9fe,stroke:#7c3aed,stroke-width:1.5px;
|
||||
classDef deny fill:#fee2e2,stroke:#dc2626,stroke-width:1.5px;
|
||||
classDef rule fill:#fff7ed,stroke:#d97706,stroke-width:1.3px,stroke-dasharray:5 4;
|
||||
```
|
||||
|
||||
这张图最该让人看出的,是匿名读这一档**不是「无所谓」、而是有三条必须守的纪律**(图上用橙色虚线框单独标出,出自安全规则、P-OPN-08 已实证):只暴露公开字段、把 PII 裁剪掉;公开读靠手动 `eq` 谓词隔离,**不能假定框架的 DataPermission 会自动生效**(它只注册在 AdminUserDO 等业务表上);跨租户读要显式收敛。这三条是匿名读端点最容易踩的坑——以为放了 `@PermitAll` 就完事,结果把私有数据或 PII 漏出去。一个要记住的细节是**登录端点本身免登**:C 端的 send-sms-code / sms-login / invite-register 三个带 `@PermitAll`(不然没法登录),但 `me` 走登录态;sms-login 是「已注册即登录、未注册自动注册」一体,成功后发真 OAuth2 token。这张图没有现行/远期边界,就是当前每个端点准入的真相速查表。
|
||||
|
||||
> **后端域图清单与状态表**
|
||||
|
||||
| # | 图名 | 家族 | 形式 | 状态 | 覆盖内容 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 后端分层与依赖(实现视角) | 架 | 引(内联 README §1) | 现 | 基座 + 13 模块 + 两段式三层;pay 未接单体 / ip 寄宿 compliance 两处特殊归属;WHAT 归架构域、本域只讲 HOW |
|
||||
| 2 | 两段式模块 -api/-server | 类 | SVG新 | 现 | 单模块剖面(-api 枚举/错误码/DTO/Feign · -server controller/service/dal/convert)+ 跨模块只依赖 -api 的越界红线 + DTO/VO/DO 三层 + 单体形态 |
|
||||
| 3 | 包名 → 端前缀自动生效 | 流 | Mer新 | 现 | controller.app/admin 包路径如何自动套 /app-api、/admin-api + 前缀反推 userType 接鉴权 |
|
||||
| 4 | 错误码分段 | 讲 | Mer新 | 现 | `1-{模块段}-***` 各模块独占段;六段源档给出 + 七段顺延推断(诚实标推断)|
|
||||
| 5 | 全平台数据模型跨域 ER(canonical) | ER | SVG新 | 现 | 五链路约 40 表跨域 ER + 全图无物理外键铁律 + 三处真相框(数据语义坑 / contracts 镜像漂移 / 两套身份)+ 源↔产物解耦 |
|
||||
| 6 | 五条业务链路 | 时 | SVG新 | 现 | 创作/发布/试玩/广告收益/数据回路 跨模块调用;唯一真原子发布 + 唯一双向边 + source_ref 对账锚点;游标/联盟SDK/检测原子桩照实标 |
|
||||
| 7 | 鉴权 OAuth2/RBAC 双模型 | 类 | SVG新 | 现 | 两类用户两套权限并存:B 端 @PreAuthorize RBAC + C 端 Service 归属隔离 + 创作白名单 + 网关双重校验=未来态纠偏 + mock 后门红线 |
|
||||
| 8 | 匿名/登录准入矩阵 | 讲 | Mer新 | 现 | 四档准入(匿名/登录/RBAC/归属)速查 + 匿名读三纪律 + 登录端点本身免登 |
|
||||
|
||||
> **状态分布**:现 ×8(后端域全部现行已建,无接/缓/建/future)。但「现行已建的结构」里照实标出了若干**设计缝与桩**——contracts DB 镜像漂移(图 5)、compliance 检测原子恒 pass / feed 游标分页桩 / 真联盟 SDK 桩(图 6)、网关双重校验是未来态而非现状(图 7)——绝不因整体为「现」就把桩画成真。**防漂移门**:本文 frontmatter 记后端域四份源档的 commit hash(README/数据模型/鉴权与权限 @ 38357c3d、13模块 @ 7ecd616e),源档变更即比对。
|
||||
|
||||
---
|
||||
|
||||
199
docs/architecture/05-前端图说.md
Normal file
199
docs/architecture/05-前端图说.md
Normal file
@ -0,0 +1,199 @@
|
||||
---
|
||||
date: 2026-06-22
|
||||
topic: 前端图说——绘境AI 架构图集(按领域拆分·05)
|
||||
status: 现行为主 · 每图具体映射源档见该图脚注 / 内联小注 · 通用图例见 00-系统总览图说
|
||||
---
|
||||
|
||||
# 05 · 前端图说
|
||||
|
||||
> 本篇是绘境AI **架构图集**的一部分(全 8 篇:[00 系统总览](00-系统总览图说.md) + 01–07 各域)。**通用图例、状态码、按角色读路径见 [00 · 系统总览图说](00-系统总览图说.md)**。
|
||||
> **本域命门(最该据图 review 的设计缝)**:试玩宿主机制建成 ≠ 合规收口;同源过渡态三债。
|
||||
|
||||
---
|
||||
|
||||
> **本域讲什么故事**:前端域回答三件事——绘境AI 有哪两个前端各服务谁、它们靠一套什么设计体系撑起一致体验(token 两层 + 组件库四层、三条数据流、三大契约、主题切换防 FOUC)、以及生成出的游戏怎么在前端被真正地玩起来(真实试玩宿主)。它的九张图里八张是「现」(设计体系已全量收口合入主干),图 2 的 token 两层 + 组件库四层是整个前端域最核心的一张。读完这个域,你知道「这套前端方案是不是想要的那个」。
|
||||
>
|
||||
> **最该据图 review 的命门缝**:前端域评审的命门在**图 8 真实试玩宿主**——它是 studio 比 demo 多出来的护城河命门,但必须看清「机制建成 ≠ 合规收口」:iframe 的 CSP、sandbox 属性、sha256 校验这套机制都已建成真跑通过,但整套现在跑在**同源过渡态**(同源 srcdoc + allow-same-origin),还有三处真实债——CSP 文档口径与代码对不上、sandbox 属性三处不一致、后端下发的 sandboxAttr 前端根本没接线,收敛方向(迁独立 usercontent 子域、CSP 改 HTTP 响应头下发、sandboxAttr 真接线)必须一起做才闭合,权威细节在第四篇沙箱与产物执行沙箱.md §8。另一处状态边界:图 9 的 **tier2 富游戏前端承载**整图是「建」(归属已定但代码未建),钉归属、不预先设计,绝不画成已建。
|
||||
|
||||
> **本域阅读约定与同步纪律**:本图说不另立设计,只把前端域的现行设计画出来。设计体系(两个前端、token 两层、组件库四层、三条数据流、三大契约、主题切换、视图地图)全部出自前端域的 canonical 设计主文档 `前端/README.md`;试玩宿主那张图(图 8)的安全隔离细节交叉引用 `架构/产物执行沙箱.md`;tier2 富游戏承载那张图(图 9)的装载侧细节交叉引用 `架构/生成引擎/引擎与运行时.md`。frontmatter 记了这三份的当前 commit hash 作为防漂移门。设计一变动,本图说与对应 SVG 必须同步更新。**本域状态分布**:前端域的设计体系已全量收口并合入主干 `dev/2.0.0`,所以**九张图里八张是「现」**(现行已建);唯一的例外是图 9——tier2 富游戏的前端承载,归属已定(归前端域)但**代码未建**,整图状态是「建」(待建),全图用虚线画、并在图顶加一条状态约定条,绝不画成已建。
|
||||
|
||||
> **本域徽章**(主要关心其中三个):**质量**(`#15803d`):换肤零改组件、向后兼容别名、迁移期新旧共存、三条数据流解耦、业务域分块导航、统一圆角矩形——设计体系的一致性与可维护性是前端域的主轴。**数据**(`#475569`):token 作为「跨端单一事实源」、品牌字符串收敛到 `common.brand` 一个 key、逐令牌权威清单只在 `tokens.css` 一处——同一份事实只有一处权威定义。**安全**(`#dc2626`):试玩宿主的 iframe 沙箱 + CSP + postMessage 双校验、路由守卫只认真实 token、匿名 `anonId` 衔接未登录态、`Icon` 禁用 emoji。前端域图说里,虚线还额外承担一层**状态语义**:图 9 整图「待建」用虚线框画;图 2 设计 token 里「跨端使命」那一格虽在「现」图里、但它本身是远期铺路(当前只服务 Web),也用虚线单独框出。一眼区分「现行已建的实心块」与「远期 / 待建的虚线框」,是本域要守的纪律点。
|
||||
|
||||
### 前端图 1 · 两个前端定位〔引·现〕
|
||||
|
||||
这张图回答「绘境AI 到底有几个前端、各是给谁的」。答案是**两个独立的前端应用**,刻意拆开,因为服务的人和承载的能力截然不同。**game-studio** 是产品前端,同时服务**创作者**(一句话生成游戏、预览迭代、发布、看收益)和**玩家**(刷短视频式的竖屏游戏信息流、点赞分享评论),用 **Vue3 + Vant**——Vant 是移动优先的 Vue 组件库,天然适配游戏流的滑动交互。**game-admin** 是管理后台前端,服务**平台运营**和**管理员**(内容审核、用户管理、数据看板、合规处置),用 **Vue3 + Element Plus**——这是绘境AI fork 的开源 Java 后台框架 Huijing 官方主推的桌面端组件库,二次开发友好。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph STUDIO["game-studio — 产品前端(消费级)"]
|
||||
direction LR
|
||||
CRT["创作者<br/>生成 / 预览 / 发布 / 收益"]
|
||||
PLY["玩家<br/>游戏信息流 / 互动"]
|
||||
end
|
||||
subgraph ADMIN["game-admin — 管理后台前端"]
|
||||
direction LR
|
||||
OPS["运营<br/>审核 / 数据看板"]
|
||||
MGR["管理员<br/>用户 / 合规处置"]
|
||||
end
|
||||
STUDIO -.->|Vue3 + Vant<br/>移动优先| DS["共同的设计语言<br/>(品牌色 / 间距 / 字体 / 圆角)"]
|
||||
ADMIN -.->|Vue3 + Element Plus<br/>桌面端| DS
|
||||
```
|
||||
|
||||
*(图源:前端/README.md §1)*
|
||||
|
||||
读这张图要抓住一条范围边界:设计体系的建设**当前聚焦 game-studio**,因为它直面大众市场、卖相与一致性要求最高、投入产出比也最高;game-admin 是内部后台工具,沿用 Element Plus 默认体系即可,只在品牌色这一层与 studio 对齐。所以下面图 2 到图 7 讲的「设计体系」,除非特别标注 admin,默认都是 studio 的。这张图没有现行 / 远期的灰度,它就是当前真相;它和这份图集里别的域的关系是——「前端域只讲两个前端长什么样、靠什么撑起一致体验」,产品对用户提供什么记在产品域、系统用什么技术搭起来记在架构域,各司其职、互不重复。
|
||||
|
||||
### 前端图 2 · token 两层 + 组件库四层(前端域最核心)〔SVG升·架构·现〕
|
||||
|
||||

|
||||
|
||||
这是整个前端域**最核心的一张架构图**,它由两条主线组成,理解了它就理解了设计体系为什么这么搭。左边是**设计 token 的两层结构**:`primitive 原始层`只描述「物理事实」(`--cyan` 是某个青色、`--sp-3` 是 12px,它只是调色板和尺子,不带含义),`semantic 语义层`描述「用途」(`--bg` 是页面背景、`--accent` 是强调色、`--danger` 是危险色、`--surface-1..3` 是从底到顶的层叠表面)。右边是**组件库的四层封装**:`L0 token`把令牌落地成 CSS 变量、`L1 Vant 适配`把 Vant 的 `--van-*` 变量映射到我们的语义层、`L2 品牌基元`封装一批带绘境AI 气质的基础组件(AppButton/Field/Icon/Card/Chip/EmptyState/NavHeader/TabBar/Skeleton/Toast)、`L3 业务组合`把基元拼成 GameCard/InteractBar/FilterTabs 这些业务组件。两条主线在**语义层交汇**——图上用最深的蓝色把语义层高亮出来,因为它是整个体系的支点。
|
||||
|
||||
这张图最该让人看出的,是 token 为什么要分两层、组件库的纪律是什么。**分两层的关键好处是「换肤时零改组件」**:组件只准引用语义令牌、绝不直接碰原始层;主题切换只需在语义层重新指向不同的原始色(暗色主题下 `--bg` 指向深色、浅色下指向浅色),组件因为只认 `--bg` 这个语义名,会自动跟着变,一行组件代码都不用动。图上把这条写进了高亮的语义层框里。**L1 那层的价值是「白嫖 Vant」**:换的只是皮肤变量,Vant 社区打磨多年的交互、无障碍、键盘支持原样吃下,不必自研——这是「复用现成」(实线)而非「自建」的典型。这张图里有一处刻意用虚线画的设计缝:左下角「跨端使命」那一格是**远期铺路、当前只服务 Web**——同一份 token 现在只喂 Web 的 CSS 变量,未来桌面 App 复用 Web 技术栈直接沿用、移动 App 把同一份 token 导出 JSON 喂 React Native / Flutter,但这些都还没做。所以它虽然画在「现」图里,本身却是远期,用虚线框 + 「远期」小标单独标出,免得有人以为跨端 App 也建好了。
|
||||
|
||||
### 前端图 3 · 三条数据流:token / theme / i18n〔SVG新·流·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「设计体系在运行期是怎么动起来的」。如果说图 2 是设计体系的**静态结构**,那图 3 就是它的**三条单向数据流**,把那张静态图里的层「跑活」。**① token 流**:`L0 token → L1 vant-theme → L2 品牌组件 → L3 业务面`,自底向上逐层消费——这是图 2 组件库四层在运行期的数据走向,组件只认下层语义名,所以换肤、跨端只动语义层一处。**② theme 流(换肤)**:`localStorage(studio.theme) → <html data-theme> → 语义层覆盖 → 全组件自动反应`,源头是用户在设置里的选择(持久化在 `localStorage`,无值时一律回落暗色),`[data-theme]` 只覆盖语义层、不碰原始层。**③ i18n 流(国际化)**:`main.ts 注册 vue-i18n → 组件用 useI18n($t) 取文案 → localStorage(studio.lang) 与 <html lang> 同步`,硬约束是禁组件内出现裸中文、缺失 key 回退 `zh-CN`、数字日期货币走原生 `Intl` 本地化。
|
||||
|
||||
这张图最该让人看出的,是三条流**互不耦合、各有清晰的源头与终点**,正是这种解耦让「换肤」和「换语言」都做到零改组件。图上还点出两处共享:theme 流和 i18n 流**共用同一套 `localStorage` + `<html>` 属性机制**——首屏内联脚本一并把 `data-theme` 和 `lang` 设好(这一步既是 theme 流防 FOUC 的关键,也是 i18n 流的语言初始化,图 6 会把这个时序单独放大);而 token 流的「为何单向」框里写明了一条贯穿全域的纪律——每层只认下层语义名,所以无论换肤、跨端还是长期演进,都只动语义层一处。i18n 流终点那个「品牌字符串收敛一处」(`common.brand` 一个 key,值 = 「绘境AI」,改名只改一处)和 token 的「跨端单一事实源」是同一种思路:同一份事实只有一处权威定义,这是前端域「数据」徽章的由来。
|
||||
|
||||
### 前端图 4 · demo 取舍〔引·讲·现〕
|
||||
|
||||
这张图回答「设计体系从哪里起步、为什么是现在这个形态」。绘境AI 手上有一份早期的投资人路演原型 `docs-design/huijing-ai-demo.html`(简称 demo),对它做了一个**决定整个前端形态的取舍判断**:**保留** demo 的「设计语言」(token 体系、`cyan→green` 的品牌渐变、暗色玻璃质感,这套视觉语言有辨识度、值得沿用),**否决** demo 的「布局范式」(它是一个桌面产品外壳——固定 236px 宽的左侧栏 + 1140px 宽的工作台,把短视频流硬塞进一个 390×660 的模拟手机框里展示,这是投资人路演用的「控制台」叙事,不是真正给大众用户的消费级界面)。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
DEMO["demo 原型<br/>huijing-ai-demo.html"]
|
||||
DEMO -->|保留| KEEP["设计语言<br/>token 体系 + cyan→green 渐变 + 暗色玻璃质感"]
|
||||
DEMO -->|否决| DROP["桌面侧栏控制台布局<br/>(236px 侧栏 + 1140px 工作台 + 模拟手机框)"]
|
||||
KEEP --> NOW["现行:响应式优先消费级 Web<br/>移动沉浸 / 桌面居中放大 / 一套组件"]
|
||||
DROP -. 远期 .-> LATER["原生桌面 App / 移动 App<br/>(仅 token 契约先就绪)"]
|
||||
```
|
||||
|
||||
*(图源:前端/README.md §3)*
|
||||
|
||||
读这张图要抓住一个产品判断:现行定位因此是**响应式优先的消费级 Web**——移动端做沉浸式全屏体验、桌面端做居中放大,一套组件适配两端;原生桌面 App、原生移动 App 都是更远期的层级,现在不做,但设计 token 提前为它们铺好了路(正是图 2 那个虚线的「跨端使命」)。这张图的设计缝在于:它是一份**记录型结论**,目的是防止后人把 demo 当成目标、反而削弱了 studio 已有的真实能力——README §7 专门列了一份「勿误砍 / 勿误判清单」,比如 studio 比 demo 多出来的「真实试玩宿主」(图 8 那套)是护城河命门、绝不能因为「demo 里没有」就砍掉,而「首页门户 / 素材中心 / 玩法模板市场屏」这些是有意的 MVP descope、不是缺陷、别去返工。看这张图时把这条边界记住:demo 给的是设计语言,不是产品蓝图。
|
||||
|
||||
### 前端图 5 · 三大契约:token / 组件 / i18n〔SVG新·类·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「设计体系对外暴露哪些不能私自破坏的约定」。它把三套契约并排画出来,每套是一个 `contract`(跨人协作时大家都遵守的约定)。**契约① token**:命名空间是 CSS 自定义属性,旧令牌(`--cyan`/`--green`/`--radius`/`--shadow`)全保留、其中 `--cyan` 被设为新语义令牌 `--accent` 的**向后兼容别名**,新增 primitive 原始层 / semantic 语义层 / 尺度令牌三组。**契约② 组件**:`AppButton` 的 props(`type/size/block/loading/disabled`)保持不变、向后兼容,primary 主按钮恢复了品牌签名渐变并补齐全部交互态(focus 焦点环 / disabled 0.5 透明 / active 按压),`Icon` 组件禁用 emoji。**契约③ i18n**:用 `vue-i18n@10`,文案按业务域划分命名空间,品牌字符串收敛到 `common.brand` 一个 key。
|
||||
|
||||
这张图最该让人看出的,是三套契约**共守一条 additive(增量式)原则**——图顶用一条绿色总纲条钉死:只增不毁,旧引用零破坏,各页面在迁移期新旧共存、逐面切换,绝不一刀切。这条原则是设计体系能平滑落地、不把现有页面改崩的根本。图上还标了两条与别的图呼应的纪律:token 契约里「三档主题 `[data-theme=light|dim]` 只覆盖语义层、不碰原始层」呼应图 2 / 图 3 的换肤机制;组件契约里那条用虚线框出的「圆角铁律」(禁药丸 / 椭圆 / 正圆混用,半径按尺寸分级 `xs/sm/md/lg/xl = 4/6/8/12/20`,默认 `md=8px`,唯一例外是 loading 旋转环保留圆形)单独立了一份规则文档 `.agents/rules/ui-uniform-rounded-rectangles.md` 约束,是创始人拍板的硬约束。这张图的设计缝提示在于:逐令牌的权威清单不在图里、以代码 `tokens.css` 为准——图只画契约的骨架与命名空间,别拿它当令牌字典用。
|
||||
|
||||
### 前端图 6 · 主题切换 [data-theme] + 防 FOUC〔Mer新·时序·现〕
|
||||
|
||||
这张图把图 3 里 theme 流那条线**单独放大成一个时序**,讲清「用户切了主题,从点击到全屏变色,中间经过哪几步、为什么首屏不会闪」。它要解决的核心问题是 **FOUC**(Flash of Unstyled Content,即页面首帧闪现未应用样式的难看瞬间):如果等到 Vue 应用挂载后才读用户的主题偏好,那首屏会先用默认色画一帧、再「啪」地跳成用户选的色,很难看。绘境AI 的解法是在 `index.html` 的首屏渲染**之前**内联一段脚本,先从 `localStorage` 把 `data-theme` 和 `lang` 设到 `<html>` 上,这样浏览器画第一帧时主题就已经是对的。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
CLICK["用户在设置内切主题<br/>(暗 / 浅 / 柔 三档)"] --> WRITE["写 localStorage<br/>studio.theme = light/dim/(暗=不写)"]
|
||||
WRITE --> ATTR1["设 <html data-theme><br/>运行期立即生效"]
|
||||
ATTR1 --> COVER["语义层 [data-theme] 覆盖<br/>--bg/--surface/--accent… 重指向"]
|
||||
COVER --> REACT["全组件自动反应<br/>(组件只认语义名 · 零改代码)"]
|
||||
|
||||
RELOAD["下次刷新 / 首次进入"] -.->|首屏渲染前| INLINE["index.html 内联脚本<br/>读 localStorage 先设 data-theme + lang"]:::boot
|
||||
INLINE -.->|第一帧就是对的色| ATTR1
|
||||
DEFAULT["无持久化值"] -.->|一律回落| DARK["暗色 (:root · 不写 data-theme)"]:::boot
|
||||
RELOAD -.-> DEFAULT
|
||||
|
||||
classDef boot fill:#f5f3ff,stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 4;
|
||||
```
|
||||
|
||||
这张图最该让人看出的,是**防 FOUC 靠的是「首屏内联脚本」这个时机点**——图上用紫色虚线把这条「下次刷新 / 首次进入」的引导路径单独画出,它不是主交互流(实线那条是「用户当场切主题」),而是页面加载时的初始化路径,两条路殊途同归地把 `data-theme` 设对。还有一处产品默认值要记住:**首次进入默认暗色**(`:root`,不写 `data-theme`),之后才由用户在设置内显式切换;无持久化值时一律回落暗色,图上用虚线标出这条回落。这张图的设计缝只有一个:跟随系统的 `prefers-color-scheme` 信号是远期增强、当前尚未接入——代码只读 `localStorage`、不读系统信号,所以现在「暗 / 浅 / 柔」三档纯由用户手动选,不会跟着系统深浅色自动变。这条边界别误判成缺陷,它是有意的现行口径。
|
||||
|
||||
### 前端图 7 · studio 视图地图〔SVG新·架构·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「studio 到底有哪些页面、怎么按业务组织、怎么导航」。它把 studio 的全部路由视图按**五个业务域**布局:**玩家消费**(Feed 游戏信息流 / ZoneFeed 专区流 / Play 试玩宿主 / Share 分享落地页)、**创作**(Create 入口 / Task 生成进度 / Preview 预览 / Project 我的项目 / Detail 详情 / Publish 发布门禁)、**平台与成长**(Login / Profile / Message / Dashboard / CreatorHome)、**studio 专区**(Material 素材中心 / Template 玩法模板中心)、**B 端定制**(BizLeads / BizCreate / BizLeadDetail)。底部 4 个 tab 标签栏(游戏流 / 创作 / 消息 / 我的)是主导航,其余视图经卡片点击、详情跳转、深链进入。
|
||||
|
||||
这张图最该让人看出的,是**视图按业务域聚类后的导航脉络与准入边界**。玩家侧有一条主消费回路:Feed → 点卡片 → Play → 点分享 → Share;消费域到创作域之间有一条跨域流转(玩家「发起同款」从消费走向创作),图上用虚线标出。准入边界是这张图的安全主轴:路由守卫只认真实 token(`isRealLogin`),匿名 `anonId` 衔接未登录态——Feed / ZoneFeed / Play / Share 匿名可达(即刷即玩不挡门、玩家无需登录就能消费,图上用绿框标),而 Create / Project / Publish / Biz / Dashboard 必须登录(未登录访问跳 `/login` 并带 redirect 回跳,图上用红框标)。这张图有两处刻意钉住的口径,看图时别误判:其一,studio 专区里的「玩法模板中心」是**品类框架入口**,与 demo 那块已被 W-CLEAN 废除的「填参式模板市场」是两回事,图上专门注明、勿混;其二,**视图计数口径**——图列了 20 个有独立路由的视图,而 README §8 写「19 视图」,差的那 1 个是 U9 新增的 CreatorHome 公开聚合主页,本图以 `router/index.ts` 实际路由为准、并把 `StatusBadge.vue`(Project 域内的子组件、非独立路由)明确排除在外。这个「20 vs 19」的小漂移是真实的、据实标出,不臆造对齐。
|
||||
|
||||
### 前端图 8 · 真实试玩宿主〔Mer新·时序·现〕
|
||||
|
||||
这张图回答「玩家点了一款 AI 生成的游戏,它怎么在浏览器里真正跑起来——而不是像 demo 那样只弹个 toast」。这是 studio 比 demo 多出来的、**护城河命门**级别的能力:真实试玩宿主。它是一条时序——`GamePlayer.vue` 先按 `versionId` 取运行包清单、对 manifest 算 sha256 与后端写包时的 checksum 严格比对(不过就退 demo 兜底),再用 `inject.ts` 把游戏代码 + SDK + 引擎 bundle 拼成 srcdoc 注入一个带 `sandbox` 属性的 iframe,挂上 `HostBridge` 桥,iframe 内 `boot()` 启动后经 postMessage 把 `game_loaded` / `game_start` 回流给宿主、宿主再 emit 给上层 Feed/Play。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant FE as Feed / Play (上层)
|
||||
participant GP as GamePlayer.vue (宿主)
|
||||
participant IJ as inject.ts (srcdoc 注入)
|
||||
participant IF as iframe (sandbox · origin=null)
|
||||
participant BR as HostBridge (桥)
|
||||
|
||||
FE->>GP: 点游戏卡片 → 进 /play/:gameId/:versionId
|
||||
GP->>GP: 取包清单 → 对 manifest 算 sha256 严格比对 checksum
|
||||
Note over GP: 校验不过 / 取包出错 → 退 demo 兜底(不向上 emit error)
|
||||
GP->>IJ: buildIframeSrcdoc(包 + SDK + engineBundle)
|
||||
Note over IJ: 函数序列化注入 + 硬编码 CSP 写进 srcdoc meta<br/>connect-src none 禁网络出站
|
||||
IJ-->>GP: 完整 HTML 文本
|
||||
GP->>IF: <iframe sandbox srcdoc> 挂载
|
||||
GP->>BR: attachBridge(origin 白名单 + schema 双校验)
|
||||
IF->>IF: boot() 启动引擎 / 兜底
|
||||
IF->>BR: postMessage(game_loaded / game_start · 经双校验)
|
||||
BR->>FE: emit('ready') / emit('start')
|
||||
IF->>BR: postMessage(game_end · 宿主轮询 latch 代发)
|
||||
BR->>FE: emit('end')
|
||||
```
|
||||
|
||||
这张图最该让人看出的,是**前端域在这里只画「宿主容器 + 桥」这一侧,安全隔离的纵深防御交叉引用沙箱篇**。前端域要关心的是:游戏与宿主之间**只有 postMessage 一条通道**,而桥把 iframe 来的每条消息当不可信边界——先过 origin 白名单(空白名单默认拒绝)、再过 schema 逐字段校验(`channel` 必须等于 `wanxiang-game-sdk`、`type` 必须在 8 个枚举内),任一不过就丢弃、绝不分发。这套**双校验**是前端这一侧的安全支点。图上还点出一个有意的过渡口径:游戏没有自己的 emit 通道发 `game_end`,所以**宿主轮询 `host.state().phase`、到 `gameover` 就 latch 一个 `game_end` 代发**(图上标「宿主轮询 latch 代发」)——这是 ref 游戏纯引擎工厂、内部没 SDK 的现实下的过渡桩,W-G1 生成主线落地后改由各品类标准信号产出。
|
||||
|
||||
这张图的设计缝必须看清,且**别误判成已合规**:iframe 的 CSP、sandbox 属性、sha256 校验这套机制都已建成、真跑通过,但**整套现在跑在「同源过渡态」**(同源 srcdoc + `allow-same-origin`),还有三处真实债——CSP 文档口径与代码对不上(文档写 `script-src 'self'`、代码实际是 `'unsafe-inline' 'unsafe-eval'`)、`sandbox` 属性三处不一致、后端下发的 `sandboxAttr` 前端根本没接线。这些债的 file:line 与收敛方向(游戏包迁独立 usercontent 子域、CSP 改 HTTP 响应头下发、sandboxAttr 前端真接线)逐条记在第四篇沙箱与 **`架构/产物执行沙箱.md` §8**,是这张图的权威细节来源。看这张图时记住:机制建成 ≠ 合规收口,安全隔离的完整故事在沙箱域,本图只画前端宿主侧的装载与桥。
|
||||
|
||||
### 前端图 9 · tier2 富游戏前端承载〔Mer新·架构·建(归属已定·待建)〕
|
||||
|
||||
这张图回答「第二条生成轨(tier2 富游戏)落地后,前端要多做哪两件事」——也是本域**唯一一张状态非「现」的图**。它整体是**建**(待建):绘境AI 除了现行的 Tier0/1 超休闲廉价线(SAA + LittleJS,产物是单包),另起了第二条生成轨 tier2(AgentScope Python 自治 agent 造多系统富游戏,产物是真 Phaser 多文件源工程)。tier2 给前端域带来两件**现在还没做、但归属已定(归前端域)**的事,所以整张图用虚线画、图顶加一条状态约定条说明整图状态。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph BAR["状态约定:整图 = 建(待建)· 虚线框 = 归属已定、代码未建 · 等 tier2 临近过 0 号 spike 再展开设计"]
|
||||
end
|
||||
|
||||
FEED["game feed 信息流<br/>(现行:承载 LittleJS 单包)"]:::now
|
||||
subgraph LOAD["① feed 双轨装载分发(待建·归前端域)"]
|
||||
direction LR
|
||||
T1["现有轨:LittleJS engineBundle 单包<br/>随 manifest 内嵌 · 已建"]:::now
|
||||
T2["第二轨:tier2 Phaser 多文件工程<br/>经独立源项目契约构建出 bundle"]:::todo
|
||||
end
|
||||
subgraph ENTRY["② studio 创作端第二轨入口(待建·归前端域)"]
|
||||
direction LR
|
||||
E1["超休闲廉价线入口<br/>(现行 Create)"]:::now
|
||||
E2["富游戏 premium 线入口<br/>(待建)"]:::todo
|
||||
end
|
||||
|
||||
FEED --> LOAD
|
||||
T1 -.->|两轨共用同一套 iframe+CSP+桥<br/>都暴露 __GameBundle / 都调 bootGameHost| SANDBOX["执行沙箱(公共件·不随轨变)<br/>详见图 8 + 沙箱篇"]:::shared
|
||||
T2 -.-> SANDBOX
|
||||
ENTRY -.->|创作端体现两条生成线分轨| LOAD
|
||||
|
||||
classDef now fill:#dcfce7,stroke:#16a34a,stroke-width:1.6px;
|
||||
classDef todo fill:#faf5ff,stroke:#7c3aed,stroke-width:1.5px,stroke-dasharray:5 4;
|
||||
classDef shared fill:#e2e8f0,stroke:#0f172a,stroke-width:2px;
|
||||
```
|
||||
|
||||
这张图最该让人看出的,是**前端域在 tier2 这件事上「钉归属、不预先设计」的克制**。两件待建的事是:其一,**feed 双轨装载分发**——feed 要同时承载两种产物(现有 LittleJS 单包 + tier2 Phaser 多文件工程),按产物类型分发到不同装载路;其二,**studio 创作端的第二轨入口**——创作端要体现「超休闲廉价线 / 富游戏 premium 线」两条生成线,给富游戏一个独立入口。图上用绿色实心块画现行已建的部分(现有 feed、LittleJS 单包轨、现行 Create 入口),用紫色虚线画待建的部分(第二轨、premium 入口),一眼区分。
|
||||
|
||||
这张图有一条最关键的边界要看清,它决定了前端域的工作量没有想象中大:**两条装载轨共用同一套执行沙箱**——不管哪条轨出来的 bundle,都暴露 `window.__GameBundle` 全局名、都调 `bootGameHost`、都跑在同一套 iframe + CSP + 桥里(图上用深色实心块把「执行沙箱」画成公共件,两轨都虚线指向它)。tier2 换的是「游戏内容怎么造出来」,换不掉「造出来之后怎么被关进笼子跑」。所以前端域要补的只是**运行时容器的双轨分发 + 创作入口**,装载与渲染的 how 在架构域、见 **`架构/生成引擎/引擎与运行时.md`**(其 §7.3 把「tier2 第二装载分支」列为待开项)与 `架构/生成引擎/tier2实现详设.md`。这张图的设计缝就是它的状态本身:**整套是待建**,详细前端设计要等 tier2 临近过 0 号 spike 再展开,现在只钉归属、不预先设计——绝不能因为图画出来了,就误以为第二条生成轨的前端已经建好。
|
||||
|
||||
> **前端域图清单与状态表**
|
||||
|
||||
| # | 图名 | 家族 | 形式 | 状态 | 覆盖内容 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 两个前端定位 | 架 | 引(内联 README §1) | 现 | game-studio(创作者+玩家·Vue3+Vant)/ game-admin(运营+管理员·Vue3+Element Plus)+ 设计体系聚焦 studio 的范围边界 |
|
||||
| 2 | token 两层 + 组件库四层 | 架 | SVG升 | 现 | primitive→semantic→component 两层 + L0/L1/L2/L3 四层,语义层交汇 + 换肤零改组件 + 跨端使命(远期虚线) |
|
||||
| 3 | 三条数据流 token/theme/i18n | 流 | SVG新 | 现 | token 自底向上 / theme localStorage→data-theme 换肤 / i18n vue-i18n 文案,三流解耦 + 共用一套 localStorage 机制 |
|
||||
| 4 | demo 取舍 | 讲 | 引(内联 README §3) | 现 | 留设计语言(token+渐变+暗色玻璃)/ 弃布局范式(桌面侧栏控制台)→ 响应式优先消费级 Web + 勿误砍清单 |
|
||||
| 5 | 三大契约 token/组件/i18n | 类 | SVG新 | 现 | additive 共守原则 + 向后兼容别名(--cyan→--accent)+ AppButton props 不变 + Icon 禁 emoji + 圆角铁律 + common.brand 单一源 |
|
||||
| 6 | 主题切换 [data-theme]+防 FOUC | 时 | Mer新(内联) | 现 | localStorage→首屏内联脚本→data-theme→语义层覆盖→组件自动反应;首次默认暗色 + 无值回落暗色;prefers-color-scheme 远期未接 |
|
||||
| 7 | studio 视图地图 | 架 | SVG新 | 现 | 20 路由视图按五业务域布局(玩家消费/创作/平台成长/studio 专区/B 端)+ 4 tab 导航 + 匿名可达/必须登录准入边界 + 20vs19 计数口径 |
|
||||
| 8 | 真实试玩宿主 | 时 | Mer新(内联) | 现 | 取包→sha256 校验→srcdoc 注入→iframe sandbox→桥双校验→postMessage 回流;game_end 宿主轮询 latch 代发;同源过渡态 + 三债交叉引沙箱 §8 |
|
||||
| 9 | tier2 富游戏前端承载 | 架 | Mer新(内联) | **建** | feed 双轨装载分发 + studio 第二轨创作入口(归前端域·待建);两轨共用同一套沙箱(公共件);钉归属不预先设计,等 0 号 spike |
|
||||
|
||||
> **状态分布**:现 ×8(图 1–8,设计体系已全量收口合入 `dev/2.0.0`)、建 ×1(图 9,tier2 富游戏前端承载归属已定但代码未建·整图虚线)。**防漂移门**:本文 frontmatter 记前端域三份源档的 commit hash(前端/README @ 15b707fd、产物执行沙箱 @ 38357c3d、引擎与运行时 @ 7ecd616e),源档变更即比对。
|
||||
|
||||
---
|
||||
|
||||
189
docs/architecture/06-运营图说.md
Normal file
189
docs/architecture/06-运营图说.md
Normal file
@ -0,0 +1,189 @@
|
||||
---
|
||||
date: 2026-06-22
|
||||
topic: 运营图说——绘境AI 架构图集(按领域拆分·06)
|
||||
status: 现行为主 · 每图具体映射源档见该图脚注 / 内联小注 · 通用图例见 00-系统总览图说
|
||||
---
|
||||
|
||||
# 06 · 运营图说
|
||||
|
||||
> 本篇是绘境AI **架构图集**的一部分(全 8 篇:[00 系统总览](00-系统总览图说.md) + 01–07 各域)。**通用图例、状态码、按角色读路径见 [00 · 系统总览图说](00-系统总览图说.md)**。
|
||||
> **本域命门(最该据图 review 的设计缝)**:元素级被阻塞部分别画成已建;8 项法定 P0 待律所。
|
||||
|
||||
---
|
||||
|
||||
> **本域讲什么故事**:运营域接在产品域与架构域之后,回答三件相互咬合的事——一款游戏被造出来之后,怎么合规上线、怎么把钱赚回来、怎么发行到各渠道。它的十一张图讲清 12+1 合规闸门的日历临界路径、合规死锁三环 + 双层定性破解、分账公式钱流(平台恒留 0.2N)、两平面两钱包三道硬边界、三线变现排序、四层护城河、发行双路线、一壳多游 L1 精选整包、变现端到端钱流地图、审核台双层审核。读完这个域,你知道「这套上线 / 变现 / 发行方案是不是想要的那个」。
|
||||
>
|
||||
> **最该据图 review 的命门缝**:运营域十一张图整体都是「现」(已拍板的现行设计逻辑),但它的特殊之处在**元素级**——同一张图里常常一半是「已建真跑」、一半是「被合规日历闸门或外部资质阻塞、尚未接线 / mock / 留待后续波次」。评审最该盯的是这条纪律:**绝不能因为整图是现行设计,就把图里那些被阻塞的部分画成已建好**——变现侧的打款 mock 桩(降级即吞真钱、必须 fail-fast)、消费钱包未接、自助购买订阅被支付闸门阻塞;审核台的检测原子全是桩恒返回 pass(框架在、判定空、处置半通);渠道侧的备案锁(把「一壳多游」从灰区可行降级为高风险待律所裁)与引擎竞标 P1 段暂停。还有一处全局阻塞:8 项 C 端法定 P0 的换血边界要等律所对两核心问给出书面意见,这是仍卡着全局的最大未决项。
|
||||
|
||||
> **本域阅读约定与同步纪律**:本图说不另立设计,只把运营域六份 canonical 设计档画出来——三件事的咬合骨架与分账公式出自 `运营/README.md`;两平面 / 两钱包 / 单位经济出自 `变现与单位经济.md`;三线钱流的工程地图出自 `变现端到端.md`;一壳多游与渠道合规红线出自 `渠道发行.md`;合规死锁与 12+1 闸门出自 `合规闸门.md`;双层审核与处置联动出自 `审核台运营.md`。frontmatter 记了这六份相关源档的当前 commit hash 作为防漂移门。设计一变动,本图说与对应 SVG 必须同步更新。**本域状态分布——整体是「现」,但布满设计缝,必须看清**:运营域不像运维域那样有「整图待接 / 整图缓做」的图;这里 **11 张图的整体状态都是「现」**(讲的都是已拍板的现行设计逻辑)。它的特殊之处在**元素级**——同一张图里常常一半是「已建真跑」、一半是「被合规日历闸门或外部资质阻塞、尚未接线 / mock / 留待后续波次」。所以本域守的纪律点是:**绝不能因为整图是现行设计,就把图里那些被阻塞的部分也画成已建好**。
|
||||
|
||||
> **本域徽章**(主要关心其中三个,个别图点到第四个):**安全**(`#dc2626`):合规即护城河、new-api 上游 API key 不明文 / 防盗刷、打款 fail-fast 绝不发假钱、审核降级朝保守、审核台端点权限强制在后端可信边界。**数据**(`#475569`):备案 / 资质合规、成本与精度域隔离(元 ≠ 分)、配置即数据(GameConfig 禁代码)、内测养行为数据飞轮、审核台账留证 ≥180 天。**成本**(`#16a34a`):单款生成成本远不到 1 元、自有端 IAA 万级 DAU 才回本的单位经济、渠道零构建生产红利、快检把审核大面在本地消化。**可靠**(`#16a34a`):变现侧 7 个资金动作各有幂等键、账户恒等式、发起 ≠ 终态的打款异步化、对账锚点链与补偿 job——这是变现端到端图的主轴。运营域的徽章里,**安全与成本两个维度是一体两面**:同一套合规资质,对自己是必须翻过的闸门(成本 / 时间),对后来者就是 6-12 个月才能补齐的护城河(安全壁垒)。本域图说里,虚线同样额外承担一层**状态语义**:凡是被合规日历闸门或外部资质阻塞、尚未接线 / mock / 留待后续波次的元素,一律虚线框 + 文字小标;红色虚线 / 红框则用于「绝不能跨越的硬边界」与「合规生死线」。
|
||||
|
||||
### 运营图 1 · 运营三件事咬合〔引·流·现〕
|
||||
|
||||
这张图回答「运营域到底要解决什么」。它把上线、变现、发行三件事的咬合关系一句话说清:**合规闸门是总闸**,没过就不能商业化;**发行决定钱从哪里进来**(自有 H5 流 + 微信 / 抖音渠道);**变现决定钱怎么分出去**(广告 / B 端 / 远期内购订阅 → 分账 → 创作者钱包 → 提现)。三条线在「现金流」这个点上汇合。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph 上线["上线 · 合规闸门(总闸)"]
|
||||
G["12+1 法定/审计闸门<br/>ICP · 实名防沉迷 · AIGC 标识<br/>大模型登记 · 算法备案"]
|
||||
end
|
||||
subgraph 发行["发行 · 流量从哪来"]
|
||||
H5["自有 H5 游戏流<br/>即时生成发布 · UGC 主场"]
|
||||
CH["微信 / 抖音小游戏<br/>精选整包发行"]
|
||||
end
|
||||
subgraph 变现["变现 · 钱怎么分"]
|
||||
AD["广告(IAA)"]
|
||||
B2B["B 端 / IP 项目制"]
|
||||
PAY["内购 / 订阅(远期)"]
|
||||
SHARE["分账 → 创作者钱包 → 提现"]
|
||||
end
|
||||
G ==>|过闸才可商业化| 发行
|
||||
H5 --> AD
|
||||
CH --> AD
|
||||
AD --> SHARE
|
||||
B2B --> SHARE
|
||||
PAY --> SHARE
|
||||
G -. 合规定性约束 .-> 变现
|
||||
```
|
||||
|
||||
*(图源:运营/README.md §1)*
|
||||
|
||||
读这张图最该抓住的是它顶上那个**反直觉但关键的战略判定**:绘境AI 的差异化护城河**不在「自有 feed 形态」本身**(那块早有现任者——摸摸鱼 / 233 / 4399 占着),而在 **AI 供给侧的成本结构**(用 agent 闭环把游戏的生成与质检全自动化,产能成本远低于人工)+ **IP 锁风保真**。运营域的所有安排,都服务于把这个成本优势,在监管窗口期内滚成内容资产与数据飞轮。这就是为什么后面的图里,合规、变现、发行三条线看似各管一摊,实则都指向同一个目标。
|
||||
|
||||
### 运营图 2 · 12+1 合规闸门依赖与日历临界路径〔SVG升·流·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「合规要过哪些闸门、按什么顺序拆」。它把 README §2.1 与合规闸门 §4 那张依赖 Mermaid 升成高保真大图,要让人一眼看出三条主线。**第一条**:经营主体已经具备(0 号闸门,创始人 2026-06-10 确认,图上用绿色实心块画出),所以下游各项可以立即并行起跑,**没有多米诺式的等待**——这是把整条链从「串行等待」变成「并行冲刺」的关键事实。**第二条**:ICP 备案是临界路径(7-20 工作日,图上用红边加粗框强调),它一通过,支付进件和广告资质两条线才能动;这条链由日历时间而非工作量决定,人再多也压不短。**第三条**:律所意见是另一个分叉点,它到位后才能定分账方案(#12)、确认大模型登记与算法备案(#9/#10)的属地路径与触发时点。
|
||||
|
||||
图上还钉了两件最该记住的事。其一是「**谁能压、谁压不动**」那条红线:AI 一秒也压不动这些闸门,材料准备(报备文案 / 备案说明 / 隐私协议占位稿)可以由 AI 代劳,但**提交、实名、付费三类动作只有创始人本人能做**——这正是日历临界路径的本质。其二是状态纪律:每道闸门的实时状态、负责人、最晚提交日是会变的活数据,**本图只画不变的依赖逻辑、不抄状态**,唯一跟踪面是《A1 闸门看板》,看板变了即真相变了。这张图的「设计缝」画在最右侧那一栏:8 项 C 端法定 P0(实名 / 防沉迷 / AIGC 标识等)当前仍是国家强制义务的全集,但它们的**换血边界要等律所对两核心问给出书面意见后才能定稿**——这是仍阻塞全局的最大未决项,图上据实标出。
|
||||
|
||||
### 运营图 3 · 合规死锁三环 + 双层定性破解〔SVG新·讲·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「为什么做得出游戏却不能直接公开经营、又怎么解开」。它是理解整个运营域合规逻辑的主干,左半边画死锁、右半边画破局。**左边的死锁是三条互相咬合的链**:第一环,UGC 小游戏无版号 → 接不进官方实名 / 防沉迷系统(版号是接入前提)→ 自有端作为运营方无法履行法定义务(有 Roblox 停服、罚没 111 万元量级的先例);第二环,IAA 免版号的豁免只在微信 / 抖音备案制内成立,搬到自有 H5 站就落进监管灰区;第三环,平台代收广告费再分账给个人创作者,等于无牌照资金归集,踩二清红线。这三环不是并列而是连环——「想合法经营 → 需版号 → UGC 拿不到 → 接不进官方系统 → 履行不了义务 → 真变现又必触发资金归集 → 碰二清」形成闭环,**任何单点突破都解不开**。
|
||||
|
||||
右边的破局办法是**双层定性**,把「自有端」和「变现渠道」在合规上彻底分开:自有端收敛为邀请制内测(邀请码注册、不公开经营、不接真钱),按「试玩 demo / 内测」定性,规避公开运营才触发的出版与防沉迷义务;真实变现全部放到渠道线(微信 / 抖音备案 + IAA),豁免通道成立、实名 / 防沉迷由渠道代管、资金经渠道结算绕开二清。这样三环锁同时解开。这张图最该让人看清的**设计缝**,是右侧那个橙色虚线框标出的事实:**「邀请制内测能否稳稳落在试玩 demo 定性上」,其成立边界(人数上限 / 链接可否分享 / 能否有任何收入)目前是工程判断、不是已经验证的法律结论**——这正是要约律所的核心两问之一。在律所书面意见到位前,自有端按「不接真钱」运行(这也是现状、不引入新增风险),公开经营推迟到什么条件满足,要等律所答。
|
||||
|
||||
### 运营图 4 · 分账公式钱流〔引·流·现〕
|
||||
|
||||
这张图回答「广告挣的钱按什么规则分」。它画的是 R3 拍板(创始人 2026-06-10)的唯一分账口径:总广告消耗 G,渠道扣 40%(微信 IAA 现金分成 60%)后平台实收净额 N = 0.6G;无 IP 时创作者拿 0.8N、平台留 0.2N,带 IP 时创作者 0.55~0.65N、IP 方从创作者份额内出 0.15~0.25N、**平台恒留 0.2N**。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
G["总广告消耗 G"] -->|渠道扣 40%| N["平台净额 N = 0.6G"]
|
||||
N -->|无 IP| C1["创作者 0.8N"]
|
||||
N -->|无 IP| P1["平台 0.2N"]
|
||||
N -->|带 IP| C2["创作者 0.55~0.65N"]
|
||||
N -->|带 IP| IP["IP 方 0.15~0.25N<br/>(从创作者份额内出)"]
|
||||
N -->|带 IP| P2["平台恒留 0.2N"]
|
||||
```
|
||||
|
||||
*(图源:运营/README.md §2.2;同口径在 变现与单位经济.md §4.1 也有公式块)*
|
||||
|
||||
读这张图要抓住它精妙的那一点——**平台恒留 0.2N**:带 IP 时,IP 方的分成是从创作者那一份里出的,所以无论带不带 IP,平台都稳定留 20%,而对外宣传创作者「拿 55%~65%」和内部「80% 分成」用的是同一个模型的两种表述,**账永远不会算成负数**。这正是规避资金纠纷与二清风险的会计前提。配套这条公式还有一条贯穿全域的**诚信红线**:对创作者宣传「能赚钱」必须用「头部款」口径(eCPM 30 时单款约需每日 12 次激励视频观看才达 5 元提现门槛,头部款可达、长尾款达不到),**绝不做普遍性承诺**。这个公式背后的单位经济结论(自有端 IAA 是万级 DAU 才回本的规模生意,约 1.33 万 DAU 覆盖 ¥4,300/月基建成本,所以近期现金只能靠 B 端),直接决定了图 6 的三线变现排序。
|
||||
|
||||
### 运营图 5 · 两平面、两钱包、三道硬边界〔SVG新·架·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「钱往外花和钱往回赚怎么隔开」。变现这件事工程上最容易出错的,是把不同方向的钱混在一起算;绘境AI 用三道永不混淆的硬边界把它钉死,图上用红色虚线把三道边界一条条画出来。**边界①**:生成计费平面(钱往外花)由 new-api 网关负责,配额只减不增、既不结算也不碰合规;收益与支付平面(钱往回赚)由后端 trade / pay 模块负责,广告分成入账、提现、结算、合规全在这里——把广告分成塞进只会扣减的 new-api 配额是范畴错误。**边界②**:收益平面内部再分两套钱包——创作者收益钱包(trade 模块,挣广告分成 / 提现用,**已建成**,图上实心绿块)与消费钱包(pay 模块,用户充值 / 扣减内购用,**尚未接入单体**,图上虚线框 + 「未接入」)。**边界③**:成本侧全程用浮点「元」(活在编排器域)、收益侧全程用 BIGINT「分」(活在后端数据库域),两个精度域跨平面对照**必须显式换算、严禁同列求差**。
|
||||
|
||||
读这张图要抓住它把**已建与未建严格分层**的纪律。已建的实心块只有创作者收益钱包那条链(广告台账 → T+1 结算 → 物化账户,带恒等式与单测);其余都用虚线标清:消费钱包未接入、自助购买订阅被支付通道阻塞(现由 admin 手动赋)、打款渠道是 mock 桩。图底那个红框是边界铁律:**trade/pay 的钱永不写进 new-api**(已 grep 确认 new-api 里没有任何收益写入路径),而且 new-api 的 redemptions / top_ups / subscription_* 表 schema 在、却从未跑过数据,**不要当成就绪能力**。这张图的设计缝就在这些虚线处:消费钱包最小闭环属 v2.0、非 MVP 必需,自助购买订阅同被日历闸门阻塞——它们是「设计已留好接口、被外部资质卡住」,不是已经建好。图上还单标了一条 P0 安全红线:new-api 的 channels 表存着上游厂商 API key,开通公网 / 创作者账户前必须确认 3000 端口未绑 0.0.0.0、ufw 已封非内网,否则公网可达即被盗刷上游账单。
|
||||
|
||||
### 运营图 6 · 三线变现排序〔引·流·现〕
|
||||
|
||||
这张图回答「三条变现线按什么先后次序走」。它画的是绘境AI 现行战略主轴的一条有先后的三线变现:**① B 端 / IP 营销小游戏(现金线·首位)→ ② 自有端邀请制内测(数据资产线)→ ③ 渠道线(规模线·微信 / 抖音 IAA)**,B 端的标杆案例还能反哺渠道线。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
L1["① B端/IP 营销小游戏<br/>现金线 · 首位"] -->|供血| L2["② 自有端邀请制内测<br/>数据资产线"]
|
||||
L2 -->|养飞轮种子| L3["③ 渠道线<br/>规模线 · 微信/抖音 IAA"]
|
||||
L1 -.标杆案例.-> L3
|
||||
```
|
||||
|
||||
*(图源:运营/README.md §3)*
|
||||
|
||||
读这张图要理解每一线**为什么是这个合规定性、它产出什么**,而排序的根因正是图 4 / 图 5 的单位经济结论。B 端排首位,是因为推广内容不是网络出版物、版号争议最小、回款最早(已有「王蓝莓」案例点火),产出现金流 + 标杆案例;自有端排第二,按「试玩 demo」定性、不公开经营、不接真钱,产出行为数据 + 产品迭代(飞轮种子,必须诚实地讲成未来式);渠道线排第三,豁免通道成立、平台代管实名 / 防沉迷,产出规模化曝光 + 真实 eCPM。这条排序对外讲给投资人的故事主轴是:单人 + AI agent 体系的资本效率(已实证)→ 用 B 端 / IP 现金线供血 → 在监管窗口期里把供给侧的成本优势,滚成内容资产与数据飞轮(**后半段是未来式,必须诚实标注**)。这张图的设计缝就在「②③ 的产出是未来式」——飞轮和规模化 eCPM 都还没发生,图与口径都把它讲成未来式,不画成既成事实。
|
||||
|
||||
### 运营图 7 · 四层护城河〔引·讲·现〕
|
||||
|
||||
这张图回答「真正难被复制的壁垒在哪」。它的核心论点是一句反直觉的判断:绘境AI 的护城河**不在生成引擎本身**(通用大模型 12-18 个月就会把纯生成能力追平),而在时间沉淀出来的四层壁垒——**数据**(玩家行为 + 质量评分 + 推荐信号,需真实流量积累、无法购买)、**网络效应**(创作者多 → 内容富 → 玩家多 → 创作者更多,飞轮转起后追赶成本指数级增长)、**资产**(模板库 + 素材市场 + IP 合约,时间沉淀型资产)、**合规**(ICP + 文网文 + 广告资质 + 渠道关系,6-12 个月才齐备)。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph 壁垒["四层护城河 — 越往后越难复制"]
|
||||
D["数据壁垒<br/>玩家行为 + 质量评分 + 推荐信号<br/>(需真实流量积累,无法购买)"]
|
||||
N["网络效应<br/>创作者多→内容富→玩家多→创作者更多<br/>(飞轮转起后追赶成本指数级增长)"]
|
||||
A["资产壁垒<br/>模板库 + 素材市场 + IP 合约<br/>(时间沉淀型资产)"]
|
||||
C["合规壁垒<br/>ICP + 文网文 + 广告资质 + 渠道关系<br/>(牌照+关系+流程,6-12 个月才齐备)"]
|
||||
end
|
||||
```
|
||||
|
||||
*(图源:运营/README.md §3「这套商业模型为什么成立」)*
|
||||
|
||||
读这张图最该看出的,是它和图 2 / 图 3 的呼应——**合规壁垒恰恰是那串闸门的另一面**:同一套资质,对自己是必须翻过的门槛,对后来者就是 6-12 个月才能补齐的护城河。所以「先把合规闸门跑通」既是上线的前置,也是在攒护城河。绘境AI 的窗口期判断是 6-12 个月,竞争路线上**不追求技术深度第一,追求生态完整度第一**——技术够用即可,生态无法复制。这张图本身没有现行 / 远期的灰度(四层壁垒都是战略判定),它的「设计缝」是:四层里只有合规壁垒是当下就在攒的(闸门在跑),数据 / 网络效应 / 资产三层都依赖真实流量与时间沉淀,是**未来式的长期优势**,不是已经筑成的墙。
|
||||
|
||||
### 运营图 8 · 发行双路线 H5 / 渠道〔引·流·现〕
|
||||
|
||||
这张图回答「游戏造出来铺到哪、怎么铺」。它画的是绘境AI 两条互补的发行路线,分工的根因是底层技术能力的硬差异:**自有 H5 流 = 海量 UGC 与「改码」的主场**(浏览器对动态生成的代码没有禁令,agent 生成的每款游戏都能即时发布、即时被刷到,这是「创作 → 生成 → 发布」闭环最完整的形态);**微信 / 抖音小游戏 = 精选整包过审的分发面**(这两个渠道对远程包会自动剥离代码、明文禁止 JS 解释器,所以渠道里只能跑「包内固定的模板代码 + 远程下发的纯数据配置」)。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
GEN["agent 生成游戏<br/>(每款独立代码)"] --> H5["自有 H5 流<br/>即时发布 · 动态代码无禁令"]
|
||||
GEN -. 精选款固化进包 .-> PKG["微信/抖音整包<br/>固定模板代码 + 远程 GameConfig"]
|
||||
PKG --> AUDIT["平台审核<br/>(备案锁:内容变更须重新备案)"]
|
||||
AUDIT --> CH["渠道游戏流<br/>一壳多游 · 主题合集"]
|
||||
H5 --> FEED["自有 feed 即刷即玩"]
|
||||
```
|
||||
|
||||
*(图源:运营/README.md §2.3;更细的分工根因与流程在 渠道发行.md §1-2)*
|
||||
|
||||
读这张图要记住对外统一措辞——**「自研流即时发布 + 双渠道精选发行」**,以及那条「不互跳、不外导」的边界。它和图 9 是一对:图 8 给发行分工的全局轮廓,图 9 把渠道线那条「一壳多游」的架构与合规红线放大。这张图的设计缝在渠道这一支:渠道线只做 L1 精选整包过审,对外口径是「主题小游戏合集」而非「开放 UGC 平台」,且受备案锁约束(详见图 9);而自有 H5 流没有备案锁、是 UGC 海量生成与 L2 改码玩法的主场。两条线的命运截然不同,绝不能混为一谈。
|
||||
|
||||
### 运营图 9 · 一壳多游 · L1 精选整包发行〔SVG新·架·现〕
|
||||
|
||||

|
||||
|
||||
这张图把图 8 渠道这一支放大,回答「渠道里的游戏到底怎么装、怎么过审」。它的起点是一个技术现实:微信 / 抖音自动剥离远程代码 + 明文禁 JS 解释器,浏览器无此禁令——所以海量 UGC 留 H5,渠道只做 L1 精选整包过审。图分三块讲清「一壳多游」:**左边是壳工程**(随包提审、微信 / 抖音各一份、固定不变),模板代码、核心层、SDK、四件 adapter 全打进包、固定不变,模板注册表只命中包内白名单;**中间是远程 GameConfig**(纯数据),玩法的差异全靠它表达,经 schema + hash 双重校验后才实例化——而它必须守住**渠道生死线**:禁一切可执行 / 可解释的字符串、禁远程下发任何代码、剧情关卡只能用有限状态机枚举,一句话「渠道里的游戏逻辑必须是数据、不能是代码」(这条红线转正后成为契约第 9c 条);**右边是平台运行时 + 备案锁 + 上架**。
|
||||
|
||||
读这张图要抓住两个最该看清的设计缝。其一是**备案锁**(图上用红边加粗框 + 「待律所裁」标出):官方规定备案完成后不支持改游戏内容 / icon / 代码,实质变更须重新备案,这条锁的是「内容」,于是把「一壳多游」从「灰区可行」**降级为「高风险待裁」**——「当日热发新游进渠道」的叙事已经收回,热发只限既有游戏的非实质参数微调,实质变更要走月级的「重新备案 + 整包提审」(具体边界待律所裁定);注意这条锁只约束渠道,**完全不影响自有 H5 流**。其二是**渠道引擎竞标 W-CH-α**(图上虚线框 + 「待裁」):C-A=LittleJS+自研 adapter 对决 C-B=Cocos 原生导出,P0 先行段五件产物已交付、6/6 PASS,但 P1 真机段七道门**暂停中、待创始人提供三件套**(微信 AppID + Win/Mac 构建机 + 安卓千元机)。这张图还点出「禁动态代码」反而带来的架构红利:每游生产是产 GameConfig + 资产、Linux 工厂全自动零构建,对 Win/Mac 的依赖只落在低频的壳版本发布层、且仅 Cocos 胜出才需——真正绕不开人工的只有平台审核节奏本身。
|
||||
|
||||
### 运营图 10 · 变现端到端钱流地图〔SVG新·时·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「钱具体怎么从一次广告 / 一笔订阅 / 一单定制,流到创作者钱包或平台营收」。它是图 5 的下钻——图 5 立两平面 / 两钱包 / 三边界的架构,图 10 画三条线的工程钱流地图,凡 mock / 未接段一律虚线标清。**① 广告分成线**(最长、已建真跑,图上整条绿色实心):玩家看广告 → ad 计费 bill()(合规校验 blockMinor + 幂等 uk_trace + 归因 getCreatorUserId)→ 落 game_ad_revenue 台账 → T+1 SettlementJob 逐笔 recordIncome 入账 → game_trade_income,中间隔着 ad→trade 的 AdRevenueApi 接缝(单体 @Primary 就地解析)。**② 订阅会员线**(trade 独管,入账已建 / 收单未建):admin 赋订阅 → 幂等账本 subscription_grant → 续期 → C 端实时查态;自助购买那一半被支付通道阻塞,现由 admin 手动赋。**③ B 端定制线**(biz 独管,图上整条红色虚线):只走业务状态机、**完全不碰钱**,收款 / 在线签章 / 分账整段留 M4,现仅 signed_offline 兜底标记。
|
||||
|
||||
读这张图要抓住右侧三条线汇合后的钱流终态,以及它最硬的可靠性纪律。三条线在创作者收益钱包 game_trade_account 上汇合,**账户恒等式 balance + frozen + total_withdraw = total_income 必须永远成立**,四个原子动作更新 0 行就抛错回滚、绝不允许「状态已置、资金未动」的半态 commit。提现 → 异步打款这一段最该看清的是「**发起 ≠ 终态**」(图上红框):审核事务内只 CAS 0→1,终态由回调驱动,且 **打款渠道是 mock 桩**(图上虚线 + 「打款 mock 桩」)——因为 PayoutClient 只有 MockPayoutClient,真实 wxpay / alipay 被合规日历闸门阻塞,但抽象已做对、补真实现即零改业务码切真;这条线的降级口径与广告线**正好相反**:广告渠道缺失降级 mock 可接受(少算收入),打款渠道缺失若降级 mock 就是吞真钱,**必须 fail-fast**。图底的控制平面画清「钱不会自己流」——三个 XXL-Job + 单体 Feign 接缝 + 打款双路驱动(正常路回调、异常路补偿 job,两条路都过 CAS 故重复驱动安全),以及那条端到端的**对账锚点链**(ad_revenue.id —source_ref→ trade_income —余额→ account 恒等式 —→ withdraw.transfer_ref,stat_date 统一取上游)。这张图的设计缝集中在三处虚线:订阅自助购买未接、打款 mock、B 端钱留 M4——它们都是「逻辑早已真实落地或抽象做对、被外部资质 / 后续波次卡住」,图上据实标层、不画成已通。
|
||||
|
||||
### 运营图 11 · 审核台:双层机审 + 锁风三档 + 人审 BPM + 处置联动〔SVG新·流·现〕
|
||||
|
||||

|
||||
|
||||
这张图回答「门开了以后,每条内容怎么一条条审过去、违规怎么处置」——它和合规闸门是两件事:合规闸门是把平台这台机器通上电的总开关(一次性、日历驱动),审核台是机器跑起来之后的质检线和安全阀(持续运转)。设计的核心不在「调三个检测器」,而在**路由**——什么内容在哪一层被放掉、什么必须往下一层送。图的主干是一个**三段瀑布**:第一层自部署快检(safe-content-ai,挡掉大面、明显 OK 放行 / 明显违规拦截,只把灰带样本往下送,价值在成本——快检把大部分流量本地消化、省阿里云调用量);第二层阿里云内容安全(灰带样本送阿里云拿有合规背书的权威结论,**接入时点是接真实公开流量前 / 渠道线③上线前**,代码接缝现在留好、实现挂 feature flag);第三层人审队列(两道机审都判 review 或锁风人工档建工单,MVP 用轻量状态机 + admin 队列、重型 Flowable 留远期,人审终裁是最高权威)。瀑布之上还有一个**锁风三档选档器**(标准 / 严格 / 人工复核),按内容的 IP 归属 + 类型自动选档,档位源现阶段是过渡表 lock_strength_policy、终态收敛进 IP 实体授权属性。
|
||||
|
||||
读这张图最该守的是它把**现状与待补严格分层**的诚实。现行已建(实心绿块)只有锁风门聚合那条框架:ComplianceGateApi.evaluate 按 block > review > pass 取最严裁决、落 game_compliance_gate_result 台账、在发布前检查被真注入——但**聚合进来的原子目前都是桩、恒返回 pass**,意味着今天的发布链对违规内容零自动拦截、纯靠人工兜底。其余全是本设计要补的待建(虚线框):双层机审的两层、人审队列底座、feed 自动降权接缝、创作者信用。处置联动这一栏要看清四类处置各自的现状落差——**下架**走 feed 现有的跨模块接缝 FeedApi.offlineRank(现成可用、封禁联动下架已在走它),**降权**则因为 setExposureLimit 现在只是管理端 HTTP 端点、不在跨模块 FeedApi 上,要 contract-first 新建 feed 降权 -api(创始人 2026-06-22 定放第一期、单独做);**封禁**台账已建,但封账号联动断着(不置 player.status=DISABLE、不连带下架全部内容,validateCreator 也不查 ban 表,所以今天封号拦不住本人继续创作,是本设计要补的两条断链);**创作者信用**现在一点没有、第一期建简单扣分台账(只记不连带、保守形态、防误伤)。图上还钉了两条贯穿铁律:**审核降级朝保守**(阿里云超时 / 报错降级到 review、绝不降级到 pass,与打款 fail-fast 同理),以及**审核状态唯一权威在 compliance**(project 只接回写、不双写,避免脑裂)。这张图的设计缝几乎布满全图——它如实画出了「框架在、判定空、处置半通」的真实现状,而非假装审核台已经建好。
|
||||
|
||||
> **运营域图清单与状态表**
|
||||
|
||||
| # | 图名 | 家族 | 形式 | 状态 | 覆盖内容 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 运营三件事咬合 | 流 | 引(内联 README §1) | 现 | 上线(合规总闸)/ 变现(钱怎么分)/ 发行(钱从哪来)三件事咬合 + 护城河在 AI 供给侧成本结构的战略判定 |
|
||||
| 2 | 12+1 合规闸门依赖 | 流 | SVG升 | 现 | 经营主体已具备(0 号)→ 全链并行;ICP 临界路径 7-20 工作日;律所分叉;8 项法定 P0 换血待律所;状态去 A1 看板 |
|
||||
| 3 | 合规死锁三环 + 双层定性破解 | 讲 | SVG新 | 现 | 死锁三环(无版号 / IAA 豁免仅渠道 / 二清)+ 双层定性(自有端内测 ‖ 变现走渠道);内测成立边界待律所问 1 |
|
||||
| 4 | 分账公式钱流 | 流 | 引(内联 README §2.2) | 现 | R3 唯一口径:N=0.6G,平台恒留 0.2N,账永不为负;头部款口径诚信红线 |
|
||||
| 5 | 两平面、两钱包、三道硬边界 | 架 | SVG新 | 现 | 生成计费(new-api)≠收益(trade/pay);创作者收益钱包(已建)≠消费钱包(未接);元≠分;边界铁律 + API key 安全红线 |
|
||||
| 6 | 三线变现排序 | 流 | 引(内联 README §3) | 现 | ① B端现金线 → ② 自有端内测数据线 → ③ 渠道规模线;②③产出诚实讲成未来式 |
|
||||
| 7 | 四层护城河 | 讲 | 引(内联 README §3) | 现 | 数据 / 网络效应 / 资产 / 合规 四层;护城河不在生成引擎;合规壁垒=闸门的另一面 |
|
||||
| 8 | 发行双路线 H5 / 渠道 | 流 | 引(内联 README §2.3) | 现 | 自有 H5 流(UGC + 改码主场)‖ 微信 / 抖音(精选整包过审);不互跳不外导 |
|
||||
| 9 | 一壳多游 · L1 精选整包发行 | 架 | SVG新 | 现 | 固定壳 + 远程 GameConfig(禁代码·9c 红线)+ 备案锁(待律所裁)+ 引擎竞标(P1 暂停)+ 零构建生产红利 |
|
||||
| 10 | 变现端到端钱流地图 | 时 | SVG新 | 现 | 三线(广告全真 / 订阅半真 / B 端仅状态机)→ 创作者钱包(恒等式)+ 提现 mock 打款;控制平面三 job + 对账锚点链 |
|
||||
| 11 | 审核台双层审核 | 流 | SVG新 | 现 | 快检 + 阿里云兜底 + 人审 BPM + 锁风三档 + 处置联动(下架现成 / 降权·信用·封账号联动待建);锁风门框架真·原子桩 |
|
||||
|
||||
> **状态分布**:11 张图整体状态全为「现」(讲的都是已拍板的现行设计逻辑);状态差异在**元素级**——已建真跑 / 框架真用实心块,待接线 / 待建 / mock / 钱留 M4 / 待律所 / 远期账用虚线框 + 文字小标。本域无「整图待接 / 整图缓做」的图,其纪律点是**不把现行设计里被合规日历闸门或外部资质阻塞的部分画成已建好**。**防漂移门**:本文 frontmatter 记运营域六份源档的 commit hash(README/合规闸门 @ 3e71715a、变现与单位经济 @ 7ecd616e、变现端到端 @ 38357c3d、渠道发行 @ 5cadf504、审核台运营 @ 15b707fd),源档变更即比对。
|
||||
|
||||
---
|
||||
|
||||
187
docs/architecture/07-运维图说.md
Normal file
187
docs/architecture/07-运维图说.md
Normal file
@ -0,0 +1,187 @@
|
||||
---
|
||||
date: 2026-06-22
|
||||
topic: 运维图说——绘境AI 架构图集(按领域拆分·07)
|
||||
status: 现行为主 · 每图具体映射源档见该图脚注 / 内联小注 · 通用图例见 00-系统总览图说
|
||||
---
|
||||
|
||||
# 07 · 运维图说
|
||||
|
||||
> 本篇是绘境AI **架构图集**的一部分(全 8 篇:[00 系统总览](00-系统总览图说.md) + 01–07 各域)。**通用图例、状态码、按角色读路径见 [00 · 系统总览图说](00-系统总览图说.md)**。
|
||||
> **本域命门(最该据图 review 的设计缝)**:观测 = 待接、k3s = 缓做,别画成现行。
|
||||
|
||||
---
|
||||
|
||||
> **本域讲什么故事**:运维域回答三件事——这套系统**部署在哪些机器上**、代码**怎么从一行 commit 变成在运行的服务**、靠**什么确认它还活着并且活得够好**。这份图说把这三件事,连同两件「设计已出但还没接上」的事(线上观测体系、k3s 迁移),用一套图加配套讲解画清楚。判断「这套运维方案是不是想要的那个」看这份图就够建立全局轮廓,逐字节的命令仍去 `deploy/` 脚本与 `.agents/skills/staging-ops.md`。
|
||||
>
|
||||
> **最该据图 review 的命门缝**:运维域的特殊之处是它同时承载「现行已建」「设计已出待接线」「收窄后缓做」三类内容,绝不能把后两类画成已建。图 6(观测)整体是**接**(待接线)、图 8(k3s)整体是**缓**(缓做、排在 W-G1 之后),其余六张是**现**。每张图内部还会用实心块 / 虚线框 + 「待接线」「缓做」小标把单个元素的状态再标一层。
|
||||
|
||||
> **本域阅读约定与同步纪律**:本图说不另立设计,只把运维域三份 canonical 设计档画出来——部署链与四机分工出自 `运维/README.md`,线上观测体系出自 `观测体系.md`,k3s 迁移出自 `k8s迁移.md`。frontmatter 记了这三份的当前 commit hash 作为防漂移门。设计一变动,本图说与对应 SVG 必须同步更新。**三种状态贯穿全图,必须看清**:运维域同时承载「现行已建」「设计已出待接线」「收窄后缓做」三类内容,绝不能把后两类画成已建。
|
||||
|
||||
> **本域徽章**(主要关心其中四个):**可靠**(`#16a34a`):隔离验证安全变体、备份 JAR 一键回滚、冒烟门退出码可卡口、观测旁路降级、k8s 共存保护与 rollout undo。**可观测**(`#0ea5e9`):OTel 统一采集、Grafana 三联下钻、夜莺告警必达——这是图 6 的主轴。**安全**(`#dc2626`):push 走 Gitea 中转(scp/rsync 被分类器拦)、Collector 集中脱敏、admin 观测入口权限守门不裸暴露后端。**成本**(`#16a34a`):内网物理机 + 人工部署而非重 CI、不硬凑第二台机器上多节点、缓存命中率哨兵——都是 < ¥5,000/月成本盒子的取舍。(另两个维度 **数据** `#475569`、**伸缩** `#7c3aed` 在 k3s 图上点到。)运维域图说里,虚线还额外承担一层**状态语义**:凡是「待接线」(观测)或「缓做」(k3s)的元素,一律用虚线框 + 文字小标画出,与「现行已建」的实心块在视觉上一眼区分开。这是本域最该守的纪律点——观测体系和 k3s 迁移都是「设计已出、代码未接」,绝不能因为画得好看就让人误以为已经建好了。
|
||||
|
||||
### 运维图 1 · 四机分工拓扑〔引·现〕
|
||||
|
||||
这张图回答「服务跑在哪里」。绘境AI 在内网阶段刻意不上云托管、不上 Kubernetes,而是用一组通过 Tailscale 连起来的物理机,按角色硬分工:**lili-mac** 是创作者本地工作站,跑开发主会话与快构建,但它会休眠合盖,所以不进 Tailscale 调度、也不承担任何「门」;**mini-desktop** 是权威验收机,staging 全栈、重型构建、浏览器端到端测试都在这里,且与生产同构;**mini-infra** 是共享基建机,Gitea / PostgreSQL / Redis / MinIO / new-api 都在这台,它绝不跑项目 app 或重型构建;**6c6g** 是常驻无人值守机,跑常开的编排、定时任务、git 操作,但禁跑重活(重型前端构建会 OOM)。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph dev["开发侧(不进调度)"]
|
||||
MAC["lili-mac · ARM<br/>主会话 / 本地 dev / 快构建<br/>(会休眠 · 不出镜像与门)"]
|
||||
end
|
||||
AGIT["Aliyun Gitea · 101.200.34.71<br/>:2222 SSH push(默认远程)<br/>:3000 HTTP 匿名读"]
|
||||
subgraph tnet["Tailscale 内网"]
|
||||
direction TB
|
||||
subgraph desk["mini-desktop · 100.64.0.7 · x86(权威验收 · 与生产同构)"]
|
||||
BE["huijing 后端单体<br/>:48080"]
|
||||
ST["game-studio 产品端<br/>:4173"]
|
||||
AD["game-admin 管理后台<br/>:4174"]
|
||||
DBL["隔离 MySQL / Redis<br/>(仅 staging)"]
|
||||
end
|
||||
subgraph infra["mini-infra · 100.64.0.8(共享基建 · 不跑 app)"]
|
||||
GIT["Gitea 代码仓<br/>(自建底座 · 非默认 push 目标)"]
|
||||
SQL["PostgreSQL / Redis"]
|
||||
OSS["MinIO 对象存储"]
|
||||
NAPI["new-api 模型网关"]
|
||||
end
|
||||
SIX["6c6g(常驻无人值守)<br/>编排 / cron / 批跑 / git<br/>(禁跑重活)"]
|
||||
end
|
||||
|
||||
MAC -- "git push(默认远程)" --> AGIT
|
||||
AGIT -- "HTTP :3000 匿名 clone/pull" --> desk
|
||||
BE -- "出网调模型" --> NAPI
|
||||
BE --> SQL
|
||||
BE --> OSS
|
||||
SIX -- "调度 / 批跑" --> desk
|
||||
```
|
||||
|
||||
*(图源:运维/README.md §1.1)*
|
||||
|
||||
读这张图要抓住一条最硬的边界:**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 已构建<br/>(字节码实证含本次改动)"] --> ISO["在隔离端口 :48090<br/>起一个新实例"]
|
||||
LIVE["live 后端 :48080<br/>全程不动 · 继续服务"]:::live
|
||||
ISO --> V{"在 :48090 验全?<br/>health 200 · 四模板就绪<br/>Flyway up-to-date · 冒烟门 12 项"}
|
||||
V -- "全过" --> SWITCH["停旧实例 → 释放端口<br/>把新实例切到 :48080"]
|
||||
V -- "任一失败" --> ROLLBACK["/tmp 备份 JAR<br/>把 :48080 恢复回去<br/>(5 分钟内 · live 本就没动)"]:::danger
|
||||
SWITCH --> REVERIFY["切后复验冒烟门<br/>+ 真 UI 走查"]
|
||||
SWITCH -.->|稳定观察一两天后| CLEAN["再删 /tmp 备份 JAR"]
|
||||
ROLLBACK --> BACK["回到改动前形态<br/>排查后重来"]
|
||||
|
||||
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)<br/>+ 基础设施成本 ¥5,000/月以内"]:::goal
|
||||
subgraph SLO["三档 SLO + Error Budget(security-and-reliability §5.1)"]
|
||||
direction LR
|
||||
S1["游戏流<br/>99.5% / 月<br/>容错预算 ≈ 3.6 小时"]
|
||||
S2["AI 生成<br/>99% / 月<br/>容错预算 ≈ 7.2 小时"]
|
||||
S3["支付<br/>99.9% / 月<br/>容错预算 ≈ 43 分钟"]
|
||||
end
|
||||
subgraph COST["成本盒子怎么撑住目标"]
|
||||
direction LR
|
||||
C1["内网物理机<br/>不上云托管"]
|
||||
C2["单体<br/>而非微服务"]
|
||||
C3["人工部署<br/>而非重 CI"]
|
||||
end
|
||||
GOAL --> SLO
|
||||
GOAL --> COST
|
||||
SLO -.->|"现状:只有一个目标数字,<br/>没有东西在持续度量它"| GAP["缺口:error budget 无人消耗与记录<br/>→ 由观测体系落地(图 6)<br/>用 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.<id>` 的 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["运营<br/>(system_users 已登录 admin)"] --> ADMIN["game-admin 控制台<br/>『观测』菜单(待建)"]:::todo
|
||||
ADMIN -->|"观测大图:嵌入只读大盘"| EMBED["Grafana 嵌入面板<br/>可用性/错误率/生成成功率"]:::todo
|
||||
ADMIN -->|"深挖跳转"| PROXY["admin 后端 auth-proxy<br/>透传 system_users 身份头(待建)"]:::todo
|
||||
PROXY -->|"可信头免登(SSO)"| GRAF["Grafana 完整大盘<br/>trace/metrics/log 三联下钻"]
|
||||
ADMIN -.->|"告警概览 API"| N9E["夜莺告警列表<br/>最近告警 / 值班状态"]
|
||||
EMBED --> GRAF
|
||||
|
||||
classDef todo fill:#fff7ed,stroke:#d97706,stroke-width:1.5px,stroke-dasharray:5 4;
|
||||
```
|
||||
|
||||
这张图要让人看出两处尚未拍板的设计缝,都还**待核**,不能当成已定。其一,**嵌入方式**:iframe 嵌 Grafana 不是写个 `<iframe src>` 就完——Grafana 默认带 `X-Frame-Options: deny` 和自身 CSP,浏览器会直接拒绝被嵌入,要让嵌入成立得开 `grafana.ini` 的 `allow_embedding` 并放 CSP `frame-ancestors`;另一条路是不嵌 iframe、改由 admin 后端查询接口取数、前端自渲核心曲线,绕开嵌入安全开关但要自己画图。其二,**SSO 免登**:倾向 auth-proxy 透传(admin 后端把已登录的 `system_users` 身份经可信请求头透给 Grafana),体验最好,但要核 Grafana auth proxy 在 iframe 场景下的 cookie/同源限制,以及 admin 代理层的安全边界——**不能让未授权 admin 用户读到观测数据,更不能把 Grafana / Prometheus 裸暴露出去**。这两处待核是这块落地前必须先定的,图上据实标出、不臆造结论。
|
||||
|
||||
### 运维图 8 · k3s 单节点迁移(收窄 + 缓做)〔SVG新·架构·缓(缓做·排 W-G1 之后)〕
|
||||
|
||||

|
||||
|
||||
这张图回答「部署形态往哪走」——也是本域**第二个最该验状态纪律**的图。它整体是**缓**:创始人 2026-06-22 拍板「范围收窄、时机缓做」,所以图上整张是**目标态、本阶段不做**,用紫色虚线框 + 「缓做」标清楚,绝不能画成现行已建。范围收窄为单节点 k3s 跑在 mini-desktop 上、只迁 staging 应用与观测栈、数据库不进集群、多节点 / 高可用 / prod 全部推迟;时机缓做、排在 W-G1(生成质量到 80%)告一段落之后(其中阶段 0 容器化零 k8s 风险、是上云前提,可先行)。
|
||||
|
||||
图分三块。**左上是目标拓扑**(紫虚线):mini-desktop 单节点 k3s(control-plane 与 worker 同机),里面是后端单体 Deployment、studio/admin Deployment、observability namespace 的三件观测 workload;旁边两个**实心块**是迁移期**全程保留**的东西——隔离 MySQL/Redis 裸容器(标「不进集群」,因为有状态迁移是另一个量级的风险)和「裸 JAR + /tmp 备份」逃生口(用红框单画,强调任一阶段、任一时刻 kubectl 出问题就 5 分钟内退回今天形态)。**右侧三块**是 mini-infra(共享基建,不进集群、不装 kubelet,集群经 ExternalName Service 走 Tailscale IP 访问它)、6c6g(不当节点、不跑 workload,只当 kubectl 控制端)、lili-mac(镜像必须 x86 出,与图 1 的边界一脉相承)。**底部是四阶段迁移路**:阶段 0 容器化(绿色实心、可先行)→ 阶段 1 装 k3s(空集群、live 仍裸跑)→ 阶段 2 后端上集群(流量切换在此、风险最高)→ 阶段 3 前端 + 观测栈上集群,每阶段都标了独立验收门与回滚手法。
|
||||
|
||||
读这张图,最要让人看清的是「**买到什么、买不到什么**」那一栏:本阶段上 k8s 买到的是声明式部署 + `rollout undo` 一键回滚 + requests/limits 共存保护 + 观测栈编排;**买不到的是高可用**——单节点 k3s 一旦节点挂了,集群和所有 workload 一起没,这和今天裸 JAR 挂了没本质区别,反而多背了一整套 k8s 控制平面的复杂度。如果创始人的预期是「上了 k8s 就更稳了」,这里要先校准:高可用要等多节点,而多节点要等有第二台有内存余量的 x86 机器(现在没有)。技术细节上还有两个被图钉住的关键决定:后端走 `hostNetwork: true`(一举两得——既直占宿主 48080 让对外端口零变化,又能连只 bind 在 `127.0.0.1` 的库,`hostAliases` 和 host-gateway 都做不到);隔离期 Pod 用 `server.port=48092` 起(避开正被 live 裸 JAR 占着的 48080),这正是图 2/图 3 的隔离验证安全变体平移到了 k8s。
|
||||
|
||||
> **运维域图清单与状态表**
|
||||
|
||||
| # | 图名 | 家族 | 形式 | 状态 | 覆盖内容 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 四机分工拓扑 | 架 | 引(内联 README §1.1) | 现 | lili-mac / mini-desktop / mini-infra / 6c6g 角色边界 + Gitea 中转 + ARM/x86 镜像门铁律 |
|
||||
| 2 | 部署链 push→pull→重建→验门 | 时 | SVG新 | 现 | Gitea 中转 + push 串行 + 字节码实证 + 隔离验证安全变体 + 真 UI 走查红线 + 目标态蓝图对照 |
|
||||
| 3 | 隔离验证安全变体 | 流 | Mer新(内联) | 现 | 新 JAR 在 :48090 验全才切、live :48080 全程不动、失败用 /tmp 备份回滚 |
|
||||
| 4 | 冒烟门 12(+1)项 | 流 | SVG新 | 现 | 基础设施/鉴权 2 项 + 五链路 10 项 + --deep 写路径 1 项 + 退出码卡口 + packageUrl 恒 null 坑 |
|
||||
| 5 | 可用性 SLO / Error Budget | 讲 | Mer新(内联) | 现 | ≥99.5% + 成本 <¥5,000/月 约束来源 + 三档 SLO + 「无人持续度量」缺口指向图 6 |
|
||||
| 6 | 观测体系 OTel→Grafana/夜莺 | 架 | SVG新 | **接** | 采集→管道→存储→看板/告警全链;唯一已就位=SAA 节点 observation,其余待接线;Collector 居中/双看板分工/旁路铁律 |
|
||||
| 7 | admin 观测入口 | 流 | Mer新(内联) | **接** | 控制台一键进盘链路 + SSO 免登 + 嵌入方式/SSO 两处待核;现状=零、整套新建 |
|
||||
| 8 | k3s 单节点迁移 | 架 | SVG新 | **缓** | 单节点 k3s + staging 应用 + 观测栈,库不进集群;四阶段迁移路;裸 JAR 兜底全程保留;买到/买不到边界 |
|
||||
|
||||
> **状态分布**:现 ×6、接 ×2(图 6/7,观测体系待接线)、缓 ×1(图 8,k3s 收窄缓做)。**防漂移门**:本文 frontmatter 记运维域三份源档的 commit hash(README/k8s迁移 @ 15b707fd、观测体系 @ 3e71715a),源档变更即比对。
|
||||
|
||||
---
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
> **这是什么**:绘境AI 全部设计文档的**唯一入口**。无论你是产品、工程师、运营,还是外部评审,都从这里开始。
|
||||
> **读它 = 当前真相**。这套文档是项目的策展层(curation layer)——经过收敛、只保留一份真值;过程稿、评审记录、历史留痕在别处(见文末"其它去哪找")。
|
||||
> **怎么用**:先看下面这张全景图认门,再按你的角色跳到对应领域的主文档,需要细节时层层下钻。
|
||||
> **看图入口(架构图集)**:全部架构图(系统级 + 七领域 ≈ 71 张图 + 讲解)已合并为一篇 → **[系统全图说](系统全图说.md)**——打开一篇、看图加讲解读懂整个系统、据图 review 设计有没有缝。
|
||||
> **看图入口(架构图集)**:全部架构图(系统级 + 七领域 ≈ 71 张图 + 讲解)按领域拆成 8 篇编号文档(`00-系统总览` + `01–07` 各域,均在本目录顶层)→ 从 **[00 · 系统总览图说](00-系统总览图说.md)**(总图 + 目录)进,看图加讲解读懂整个系统、据图 review 设计有没有缝。
|
||||
|
||||
---
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
---
|
||||
date: 2026-06-22
|
||||
topic: 架构图集——全域目录 + 图清单 + 每图讲什么(确认稿 v2,已纳 Codex+Opus 双评审整改)
|
||||
status: 第一期已收口 = 单一全量主档 docs/architecture/系统全图说.md(创始人 2026-06-22 反馈:多文件跨子目录引用不渲染图 → 把"导览式总图叙 + 分散各域图说"改为合并一篇·删冗余;§4 图清单仍是有效图账)· 第二期生成引擎子树归在飞 session 只链不双写
|
||||
status: 第一期已收口 = 架构图集按领域拆成 8 篇编号文档,全放 docs/architecture 顶层(00-系统总览=总图+目录 / 01-产品…07-运维各域)。结构经创始人三次反馈收敛:导览式多文件跨子目录不渲染 → 合并一篇嫌太大 → 终态拆多篇都放顶层编号(顶层文档引子目录 assets 单向下引故真渲染);§4 图清单仍是有效图账 · 第二期生成引擎子树归在飞 session 只链不双写
|
||||
---
|
||||
|
||||
# 架构图集 · 全域目录与图清单(确认稿 v2)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user