# SimpleLite 三端系统架构设计

> **Migu2.0 仓库说明**：平台后端已拆至本仓库，工程名为 **`MiGu.Server`**（原 `Platform.Server`）。SimpleLite 与前端源码仍在兄弟仓库 `Simple`。下文中的 `MiGu.Server` 即指本仓库 `MiGu.Server/` 目录。

> 文档版本：v1.7.0  
> 更新日期：2026-05-20  
> 范围：SimpleLite（主程序 / 设计端 / 调度引擎宿主 / 进程编排器）+ Platform（业务平台 · 同时承载管理员前端 platform-vue 与运营前端 rcsmonitor-vue · 共用一套 WebAPI · **主入口为 MiGu.Server，登录后拉起 SimpleLite**）

> v1.7.0 变更（多主题色板 · 工业紫默认）：
> - **6 套可切换主题**：`themes.ts` 定义色板（工业紫、深邃蓝、翡翠绿、熔铁赤、石墨钢、琥珀金）；默认 **工业紫色** `#6a1b9a`（比 v1.6.2 的 `#641393` 更深更饱和，解决登录后内容区配色过淡）。
> - **运行时注入**：`applyThemeVars()` 向 `:root` 写入 `--mg-*`；`ui` store 的 `themeId` 持久化到 `localStorage`（键 `simple.ui.state`）。
> - **ThemeSwitcher**：`AppShell` 顶栏下拉切换；`main.ts` 启动时 `applyCurrentTheme()`。
> - **壳层变量化**：`AppShell` 侧栏/顶栏/光晕/菜单由硬编码紫改为 `var(--mg-*)`；登录页 `BlankLayout` / `LoginView` 光球与 hero 同步走变量（待办见 §18）。
> - 详见 §17.7、§18「实现进度与待办」。

> v1.6.2 变更（全站统一玻璃风）：  
> - **品牌主色回归 v1.6 的 `#641393`**：与登录页 hero 一致；保留 FRLD logo 仍在侧栏左上角；侧栏 / 顶导 / 内容卡片采用统一玻璃设计令牌（`--mg-glass-*`、`--mg-radius` 14/20px）。  
> - **整站背景深紫渐变**：`body` 固定 `radial-gradient + linear-gradient(135deg,#1a0930 → #2d1456 → #0f0420)`；AppShell 内悬浮三颗低亮度光球（drift 动画 22s）增加层次感。  
> - **登录页玻璃 hero 还原**：双栏 hero · 「迷」徽标 · 18 颗 twinkle 星 · 三色 drift 光球 · `mg-glass-lg` 主卡（白色 8% 半透明 + 28px blur + 双层 inset 边框）。  
> - **AppShell 玻璃化**：侧栏 `rgba(22,4,31,0.85→0.88)` 深紫渐变 + 18px backdrop blur + 菜单 active 状态紫色渐变背景 + 3px inset 紫光；顶导 `rgba(22,4,31,0.6)` 玻璃；底栏 `rgba(22,4,31,0.25)` 玻璃；用户头像 / 标签 / dropdown 全部玻璃化。  
> - **内容区卡片自动玻璃化**：`<el-main class="main mg-content">` 容器内所有 `el-card / el-statistic / el-table / el-descriptions / el-input / el-tag / el-progress / el-collapse / el-radio-button / el-input-number / el-switch / el-pagination` 均沿用紫黑半透明 + 14px 圆角 + hover 上浮（translateY -2px）+ shadow 升级；KPI 行 `class="kpi-row"` 内 `el-statistic` 自动玻璃卡。  
> - **路由切换微动效**：`<router-view>` 包裹 fade-up（250ms cubic-bezier .25,.8,.25,1），轻盈不花哨。  
> - 详见 §17「视觉规范」。

> v1.6.1 变更（视觉对齐 FRLD · 已在 v1.6.2 中部分回退）：  
> - **侧边栏左上角加 FRLD（法睿兰达 FAIRYLAND）logo**：`public/FRLD-logo-white.png` 展开态 36px 高、`public/FRLD-logo-white-no_title.png` 折叠态 26px 高 + 缩写「迷毂」。Logo 来源 `E:\ddms\frontend\public`。**v1.6.2 保留 FRLD logo，但取消 #7c3aed 主色与 ddms 风格菜单态，全部回到 v1.6 玻璃风。**

> v1.6 变更（品牌 & 视觉规范）：  
> - **产品品牌命名定为「迷毂」**：Vue 外壳产品代号、登录窗 / 侧边栏 logo、`<title>`、用户可见文案、`favicon` 全部统一为「迷毂」；后端工程标识 `MiGu.Server` / 前端工程目录 `simple-platform-vue` 不变（避免影响 csproj/pnpm 包名）。  
> - **品牌主色紫色系（v1.6 初版 #641393，v1.6.1 调整为 #7c3aed）**：全站统一紫色调；Element Plus 通过 CSS 变量覆盖（`--el-color-primary` 与 `--el-color-primary-rgb` 双重保险）；状态色保持系统默认。  
> - **登录窗背景**：使用品牌图片资源 `frontends/apps/simple-platform-vue/public/login-bg.jpg`（原始素材 `wall_Beach.jpg`，1.8 MB）+ 紫色径向 + 线性渐变叠加。  
> - 详见 §17「视觉规范」。

> v1.5 变更：  
> - **持久层多 Provider 支持**：抽象层基于 EF Core，新增对 **MySQL / PostgreSQL / SQL Server** 的原生支持；SQLite 仍为默认/边缘单机首选。  
> - **高可用方案按 DB 矩阵化**：除 ROSE HA（SQLite 块级镜像）外，新增 **MySQL InnoDB Cluster / MGR**、**PostgreSQL Patroni / 流复制**、**SQL Server Always On AG** 三种企业级 HA 路径；现场可根据已有 IT 基础设施挑选。  
> - 新增 §7.4–§7.7 四类 DB 部署形态详述、选型矩阵、连接串与配置示例、迁移注意事项。

> v1.4 变更（保留）：  
> - **明确进程编排归属**：Platform 后端进程 `MiGu.Server.exe` 不再被视为"独立的业务平台服务"，而是 SimpleLite 内置 `SystemMission`（`StartPlatformMission`）拉起、被 SimpleLite Bootstrapper 守护的**受控子进程**；RCSMonitor 不存在独立后端进程，复用 MiGu.Server。  
> - **整体定位章节重写**：明确"两类后端可执行文件 + 一个进程编排者"的关系，避免读者误以为 Platform 是用 Windows Service / systemd 独立部署的服务。

> v1.3 变更（保留）：  
> 1. **取消 RCSMonitor.Server**：`rcsmonitor-vue` 不再有独立后端进程，直接连 MiGu.Server；由 JWT 中的 `scope=RCSMonitor` + 角色权限码 + `WidgetGrant` 三层限制可见控件与可调用 API。  
> 2. **3D 渲染基座定为 webVRender**：复用 SimpleLite WebTerminal 已经提供的 webVRender，以 Web Component / iframe 嵌入到 platform-vue 与 rcsmonitor-vue，两端共享同一份 Workspace 协议（PutModel / PutPointCloud / SetCamera 等 DTO）。  
> 3. **反向代理选定 YARP**：MiGu.Server 内置 [YARP](https://microsoft.github.io/reverse-proxy/) 做 `/api/sl/*` → SimpleLite WebAPI 的反代；带鉴权与审计中间件。  
> 4. **运行模式持久化到 `simple.json`**：登录窗"记住模式"勾选后写入 `simple.json.runMode`；下次启动直接进入。  
> 5. **Web-Enabled 下严禁同时本地操作**：CycleGUI 主窗只剩"服务状态窗"，所有业务面板硬性隐藏；不提供"临时启用本地 UI"开关。  
> 6. **共享前端组件库**：使用 pnpm workspace + `frontends/packages/sl-controls`，封装 Workspace3D / 地图 / 任务 / CAD 等可复用 Vue 组件。

---

## 目录

1. [总体目标与拆分原则](#1-总体目标与拆分原则)
2. [顶层系统架构（C4 - 容器视图）](#2-顶层系统架构c4---容器视图)
3. [启动登录与运行模式](#3-启动登录与运行模式)
4. [进程拓扑与生命周期](#4-进程拓扑与生命周期)
5. [三端职责矩阵](#5-三端职责矩阵)
6. [共享内核分层](#6-共享内核分层)
7. [数据库与高可用（多 Provider）](#7-数据库与高可用多-provider)
8. [用户 / 权限模型（含控件级权限）](#8-用户--权限模型含控件级权限)
9. [平台配置中心](#9-平台配置中心)
10. [关键交互序列](#10-关键交互序列)
11. [通信协议矩阵](#11-通信协议矩阵)
12. [部署拓扑](#12-部署拓扑)
13. [仓库与解决方案规划](#13-仓库与解决方案规划)
14. [落地路线图](#14-落地路线图)
15. [已确认决策](#15-已确认决策)
16. [现有代码影响面](#16-现有代码影响面)
17. [视觉规范（v1.6 新增）](#17-视觉规范v16-新增)
18. [实现进度与待办（对照代码库）](#18-实现进度与待办对照代码库)

---

## 1. 总体目标与拆分原则

### 1.1 整体定位

一套为 AGV/AMR 现场打造的「**设计 → 调度 → 运营监控**」三端协同系统。

**三个"端"对应三套用户体验，但只有两类后端可执行文件，且都由 SimpleLite 统一编排：**

| 端 | 前端载体 | 后端可执行文件 | **启动者** | 角色 | 写权限 |
|----|----------|----------------|------------|------|--------|
| **SimpleLite 桌面端** | CycleGUI 客户端 | `SimpleLite.exe` 自身 | 用户双击 / 服务管理器 | 主程序 + 调度引擎宿主 + 全功能 WebAPI 提供者 + **进程编排器（Bootstrapper + SystemMission）** | **全功能** |
| **Platform 管理端** | `platform-vue` (Vue 3 SPA) | `MiGu.Server.exe` | **SimpleLite 内置 `SystemMission.StartPlatformMission` 拉起**（Web-Enabled 时自动 spawn；崩溃由 SimpleLite Watchdog 重启） | **SimpleLite 全能力套壳**：管理员侧 Vue 前端复刻所有设计/调度控件 + 业务平台特有能力（配置中心 / 外部对接 / 库位 / 账号） | **全功能**（等价 SimpleLite） |
| **RCSMonitor 运营端** | `rcsmonitor-vue` (Vue 3 SPA) | **共用 `MiGu.Server.exe`**（无独立后端进程） | 随 MiGu.Server 一起被 SimpleLite 拉起 | 运营监控前端：按 `scope=RCSMonitor` + 角色权限 + WidgetGrant 三层裁剪 UI；可对任务/车辆执行白名单运维动作 | **受限**（仅运维白名单） |

**关键澄清（v1.4 重点）：**

- **后端可执行文件只有 2 个**：`SimpleLite.exe`、`MiGu.Server.exe`。  
- **进程启动只有 1 个真正的入口**：用户/服务管理器只启动 `SimpleLite.exe`，MiGu.Server 由 SimpleLite 自己拉起，**不需要也不允许独立安装为 Windows Service**。  
- **进程编排归属 SimpleLite**：`SystemMission` 是 SimpleLite 自带的 Mission 体系扩展（与业务 Mission 区分开），专门负责拉起/守护/优雅停止 MiGu.Server。Bootstrapper 监听心跳、按指数退避重启、统一记录 OpsAuditLog。  
- **Vue 两份产物，同一进程托管**：MiGu.Server 在 `/admin/*` 路径下托管 `platform-vue`，在 `/monitor/*` 路径下托管 `rcsmonitor-vue`。  
- **鉴权与限权完全在 MiGu.Server 完成**：RCSMonitor 不持有任何独立后端代码（没有 `RCSMonitor.Server.exe`、没有独立库）。  
- **Desktop-Only 模式下，SystemMission 不触发**：MiGu.Server 根本不会启动，Vue 端无法访问。

> 一句话：**用户点 SimpleLite.exe，由 SimpleLite 通过 Mission 把 Platform 后端拉起来；Platform 后端再把两套 Vue 端服好。**

### 1.2 核心拆分原则

1. **Crash-Isolation（搞不崩主服务）**  
   Platform / RCSMonitor 对**地图/任务/车辆等写操作**都通过 SimpleLite 的 `/api/*` 网关；主服务侧做白名单 + 幂等校验 + 频次限流 + 审计。Platform-Vue 走完整 API 集，RCSMonitor-Vue 仅限运维白名单 `/api/ops/*`。

2. **共享数据模型，独立运行时**  
   地图、车辆、任务三端共用 `SimpleCore` 的 DTO；调度引擎只在 SimpleLite 里跑，Platform 只持有"投影"。

3. **库分离 + Provider 抽象**（详见 §7）  
   - `simple_main` 由 SimpleLite 持有；`platform` 由 Platform 持有（含 RCSMonitor 审计/标注）；不再有独立的 `rcsmonitor_local`。  
   - 持久层基于 **EF Core**，**通过 Provider 切换底层数据库**：默认 **SQLite**（边缘单机，配 ROSE HA）；可选 **MySQL / PostgreSQL / SQL Server**，匹配现场已有 IT 基础设施与企业级 HA 能力（详见 §7.4–§7.7）。  
   - 高可用方案随 Provider 不同：SQLite 用 ROSE HA；MySQL 用 InnoDB Cluster；PostgreSQL 用 Patroni；SQL Server 用 Always On AG。

4. **统一协议层**  
   所有进程间调用统一 **WebAPI（REST/JSON）+ WebSocket 事件流**；Vue 端直接对接 Platform 后端的 REST + WS；Platform 后端用 **YARP** 反代 SimpleLite 的设计/调度 API。

5. **统一身份**  
   `SimpleShared.Auth` 提供 JWT + RBAC；Platform 是主权限源（在线时），SimpleLite 在 Desktop-Only 下用本地用户表降级。

6. **运行模式互斥（强约束）**  
   - **Desktop-Only**：CycleGUI 客户端独占；WebAPI / Platform **不启动**。  
   - **Web-Enabled**：WebAPI 启动；Platform 子进程启动；CycleGUI 客户端**所有业务面板硬性隐藏**，仅保留"服务状态窗"；**不允许"临时启用本地 UI"开关**——任何本地操作必须重启进设计模式。  
   - 模式由**启动登录界面**选择并持久化到 **`simple.json.runMode`**；下次启动可勾选"记住选择"直接进入。

7. **控件级权限**  
   Platform / RCSMonitor 登录后向 `SimpleShared.Auth` 拉取 `EffectivePermissions { allowedOps[], visibleWidgets[] }`；Vue 渲染器按集合裁剪面板、按钮、菜单、右键项。

---

## 2. 顶层系统架构（C4 - 容器视图）

```mermaid
flowchart TB
    subgraph Users["使用方"]
        U1["现场工程师 (CycleGUI 桌面)"]
        U2["管理员 (浏览器)"]
        U3["运营 / 班组长 (浏览器)"]
        U4["第三方 MES / WMS / RCS"]
    end

    subgraph Host["主控宿主机 / 边缘服务器"]
        subgraph SL["SimpleLite 主进程 (CycleGUI + ASP.NET Core 8)"]
            direction TB
            SL_Login["启动登录窗<br/>(模式选择 Desktop / Web)"]
            SL_UI["CycleGUI 客户端<br/>(Desktop-Only: 全功能<br/>Web-Enabled: 仅状态窗)"]
            SL_Boot["Bootstrapper<br/>(进程守护 + 心跳)"]
            SL_Sched["SimpleScheduler 调度引擎"]
            SL_Domain["领域服务<br/>(SimpleCore + 命令总线)"]
            SL_API["全功能 WebAPI + WS Hub<br/>(Kestrel)<br/>(仅 Web-Enabled 启动)"]
            SL_WV["webVRender Web Terminal<br/>(已有 :8223)<br/>(Vue 端嵌入)"]
            SL_DB[("SQLite: simple_main.db<br/>WAL")]
        end

        subgraph PL["Platform 后端 (ASP.NET Core 8 WebAPI)"]
            direction TB
            PL_Static["静态资源<br/>/admin/* → platform-vue dist<br/>/monitor/* → rcsmonitor-vue dist"]
            PL_API["Platform WebAPI<br/>(配置中心 / 外部对接 / 库位 / 账号)"]
            PL_YARP["YARP 反代<br/>/api/sl/* → SimpleLite WebAPI<br/>+ Auth/审计中间件"]
            PL_Auth["SimpleAuth<br/>(JWT 签发 + Scope 校验)"]
            PL_Adp["外部系统适配器<br/>(MES / WMS / RCS)"]
            PL_DB[("SQLite: platform.db<br/>WAL")]
        end
    end

    subgraph Vues["两份 Vue 编译产物 (同一进程托管)"]
        AdminVue["platform-vue<br/>(管理员全功能)"]
        MonVue["rcsmonitor-vue<br/>(运营按权限)"]
    end

    subgraph External["外部"]
        Veh["AGV 车端"]
        TPS["第三方设备<br/>(电梯 / 充电桩 / IO)"]
    end

    U1 --> SL_Login
    SL_Login --> SL_UI
    U2 -- "https://host:8080/admin" --> PL_Static
    U3 -- "https://host:8080/monitor" --> PL_Static
    U4 -- "REST / OPC-UA" --> PL_API
    PL_Static --> AdminVue
    PL_Static --> MonVue

    AdminVue -- "REST + WSS" --> PL_API
    MonVue -- "REST + WSS (scope=RCSMonitor)" --> PL_API
    AdminVue -. "iframe / WebComponent" .-> SL_WV
    MonVue -. "iframe / WebComponent (read-only)" .-> SL_WV

    PL_API --> PL_Auth
    PL_API --> PL_YARP
    PL_YARP -- "WebAPI + WS<br/>(Web-Enabled 时)" --> SL_API
    PL_API --> PL_DB
    PL_API --> PL_Adp

    SL_Boot == "SystemMission.StartPlatformMission<br/>spawn + heartbeat + watchdog" ==> PL

    SL_API <--> SL_Sched
    SL_API <--> SL_Domain
    SL_Domain --> SL_DB

    SL_Sched -- "TCP / WS / OPC-UA" --> Veh
    PL_API --> TPS
```

**要点：**

- **只有两个后端可执行文件**：`SimpleLite.exe` 与 `MiGu.Server.exe`；RCSMonitor 不再有独立后端。
- **`MiGu.Server.exe` 由 SimpleLite 的 SystemMission 拉起**：用户只启动 SimpleLite；Web-Enabled 时 `StartPlatformMission` 自动 spawn MiGu.Server，子进程心跳异常由 Bootstrapper 重启。
- **`PL_Static` 同一进程双 SPA 托管**：浏览器访问路径决定加载哪份 dist，登录时也按路径决定 `scope` 参数。
- **`PL_YARP` 把 `/api/sl/*` 反代到 SimpleLite**：YARP 在请求转发前后挂中间件做 JWT 校验、权限码二次确认、写操作审计、`Idempotency-Key` 透传、Scope 检查（RCSMonitor 的请求仅允许命中 `/api/ops/*` 这一前缀）。
- **3D 由 SimpleLite 的 webVRender 提供**：Vue 端通过 iframe 或 Web Component 嵌入 webVRender 的页面，业务交互（选择、点击坐标等）通过 `postMessage` 与 Vue 桥接。
- **Desktop-Only 模式**：`SL_API`、`PL` 都不启动；Vue 无法访问；CycleGUI 是唯一入口。
- **Web-Enabled 模式**：CycleGUI 退化为状态窗；所有业务操作通过 Vue 完成；硬性不允许同时本地操作。

---

## 3. 启动登录与运行模式

### 3.1 启动流程

```mermaid
flowchart TB
    Start([SimpleLite.exe 启动]) --> CheckPrev{simple.json 中<br/>runMode 已记忆?}
    CheckPrev -- 否 --> Login[弹出登录窗<br/>SimpleLite Boot Login]
    CheckPrev -- 是 --> AutoLogin[自动按记忆模式登录<br/>仍需鉴权身份]
    Login --> Form
    AutoLogin --> ModeSwitch

    subgraph Form[登录窗内容]
        F1[用户名 / 密码]
        F2[运行模式 RadioButtons]
        F2a[Desktop-Only]
        F2b[Web-Enabled]
        F3[记住选择 CheckBox<br/>勾选后写 simple.json.runMode]
        F4[登录按钮]
    end

    Form --> Auth[本地用户表认证<br/>SimpleShared.Auth]
    Auth -- 失败 --> Login
    Auth -- 成功 --> Persist{勾选了<br/>记住选择?}
    Persist -- 是 --> WriteCfg[写 simple.json<br/>runMode + rememberRunMode=true]
    Persist -- 否 --> ModeSwitch
    WriteCfg --> ModeSwitch

    ModeSwitch{运行模式?}
    ModeSwitch -- Desktop-Only --> Path1
    ModeSwitch -- Web-Enabled --> Path2

    subgraph Path1[Desktop-Only 路径]
        D1[启动 CycleGUI 全功能 UI]
        D2[启动调度引擎]
        D3[加载场景 / 插件]
        D4["不启动 WebAPI / Platform"]
    end

    subgraph Path2[Web-Enabled 路径]
        W1[启动 Kestrel + WebAPI]
        W2[启动调度引擎]
        W3[加载场景 / 插件]
        W4[启动 WebTerminal]
        W5[启动 MiGu.Server.exe]
        W6[CycleGUI 仅渲染服务状态窗<br/>所有业务面板硬性隐藏]
        W7[等待 Vue 端登录]
    end
```

### 3.2 登录界面（CycleGUI Panel）

字段与控件：

| 元素 | 控件 | 说明 |
|------|------|------|
| 标题 | Label | "SimpleLite · 启动登录" |
| 用户名 | TextInput | 默认上次登录用户 |
| 密码 | TextInput (password) | — |
| 运行模式 | RadioButtons | `Desktop-Only` / `Web-Enabled` |
| 记住选择 | CheckBox | 勾选后写入 `simple.json.runMode` 与 `simple.json.rememberRunMode=true` |
| 监听地址（Web-Enabled 显示） | TextInput | 默认 `0.0.0.0` |
| WebAPI 端口（Web-Enabled） | NumberInput | 默认 `7001` |
| Platform 端口（Web-Enabled） | NumberInput | 默认 `8080`（同时承载 admin/monitor 两份 SPA） |
| 高级（Web-Enabled 折叠） | Collapsing | webVRender 端口 / Swagger 是否启用 / CORS 白名单 |
| 登录按钮 | Button | 通过后销毁登录窗，进入选定模式 |
| 退出按钮 | Button | 不进入主程序，退出进程 |

> 实现位置：新增 `SimpleLite/UI/BootLoginPanel.cs`，由 `Program.Main` 在 `Enssentials.Load` 之后、`Startup.EntryPoint` 之前调用 `GUI.PromptAndWaitPanel(BootLoginPanel.Build())`（阻塞式模态）。

#### simple.json 增量字段

```json
{
  "runMode": "WebEnabled",          // "DesktopOnly" | "WebEnabled"
  "rememberRunMode": true,
  "webApi": {
    "host": "0.0.0.0",
    "port": 7001,
    "wsPort": 7002,
    "enableSwagger": false
  },
  "platform": {
    "port": 8080,
    "wsPort": 8081
  },
  "webVRender": {
    "port": 8223
  }
}
```

### 3.3 模式切换与互斥保证（强约束）

| 场景 | 行为 |
|------|------|
| Desktop-Only 运行中 | Kestrel 不监听任何端口；MiGu.Server 不 spawn；尝试连接 7001/8080 直接 ECONNREFUSED |
| Desktop-Only → Web-Enabled | **必须退出 SimpleLite 重新登录**；不支持热切（避免半启动状态） |
| Web-Enabled 运行中 | CycleGUI 主窗只显示状态窗（运行时长 / 在线用户 / 端口 / 主备状态）+「停止」按钮 |
| Web-Enabled 下用户尝试本地控件 | **所有业务面板硬性不渲染**；Workspace 视口也不显示；用户无法通过任何方式重新启用 |
| Web-Enabled 异常退出 | Watchdog 重新拉起，恢复到 Web-Enabled；不强迫用户重选 |
| 想取消"记住模式" | 启动时按住 `Shift` 或运行 `SimpleLite.exe --re-login` 强制弹出登录窗 |
| 远程开关模式 | Platform 管理员可以发 `POST /api/sl/runmode/reset` 把 `rememberRunMode` 置为 `false`，**仅在下次重启时生效** |

### 3.4 服务状态窗（Web-Enabled 唯一可见的 CycleGUI 面板）

```text
┌──────────────────────────────────────────┐
│  SimpleLite Service Status               │
├──────────────────────────────────────────┤
│ 模式:       Web-Enabled                  │
│ 启动时间:   2026-05-18 09:00:00          │
│ 运行时长:   00:23:15                     │
│ WebAPI:     http://0.0.0.0:7001 [OK]     │
│ WebSocket:  ws://0.0.0.0:7002   [OK]     │
│ webVRender: http://0.0.0.0:8223 [OK]     │
│ Platform:   :8080 [Running, pid=12345]   │
│ 节点角色:   Active (ROSE)                │
│ 在线 Vue 客户端: 7 (admin=3, monitor=4)  │
│ 调度循环: 50Hz  | 任务: 14 / 32          │
│                                          │
│ [Open Logs]  [Restart Web]  [Shutdown]   │
└──────────────────────────────────────────┘
```

> 状态窗**不包含**"启用本地 UI"按钮——切回设计模式必须重启进程并选择 Desktop-Only。

---

## 4. 进程拓扑与生命周期

### 4.1 进程关系图

```mermaid
flowchart LR
    A["SimpleLite.exe<br/>启动 + 登录"] --> Mode{运行模式}

    Mode -- Desktop-Only --> D[CycleGUI 全功能 UI]
    D --> SchedD[调度引擎]
    D --> DB1D[(simple_main.db)]

    Mode -- Web-Enabled --> WHost[Kestrel + WebAPI :7001/7002]
    WHost --> SchedW[调度引擎]
    WHost --> DB1W[(simple_main.db)]
    WHost --> WV[WebTerminal :8223<br/>webVRender]
    WHost --> StatusPanel[CycleGUI 状态窗]

    subgraph SysMis["SimpleLite SystemMission 体系"]
        E["StartPlatformMission<br/>(SystemMission 子类)"]
        SM_Reg["SystemMissionRegistry"]
        SM_Hb["HeartbeatChannel<br/>(named pipe)"]
    end
    WHost --> SysMis
    E ==> P["MiGu.Server.exe<br/>(ASP.NET Core WebAPI + YARP)<br/>:8080/8081"]
    P --> PStatic["静态托管 2 份 dist:<br/>/admin → platform-vue<br/>/monitor → rcsmonitor-vue"]
    P --> PDB[(platform.db)]
    P <-. JSON heartbeat .-> SM_Hb

    subgraph 守护
        W["ProcessWatchdog<br/>(指数退避重启 + 优雅停止)"]
    end
    SysMis --- W
    W -. monitor .- P
```

### 4.2 SystemMission 体系（v1.4 新增章节）

SimpleLite 现有 `Mission` 是业务任务（运送/搬运），新增 **`SystemMission`** 作为同一基类的"系统级 Mission"，用于拉起并守护进程级服务。它**不参与调度引擎的 DispatchLoop**，由 Bootstrapper 直接驱动。

**关键类：**

| 类型 | 类型 / 命名空间 | 职责 |
|------|------------------|------|
| `SystemMission`（抽象） | `SimpleLite.RCS.SystemMissions` | 继承自现有 `Mission`，新增 `Spawn() / Stop() / Heartbeat()` 等抽象方法 |
| `StartPlatformMission` | `SimpleLite.RCS.SystemMissions` | 拉起 `MiGu.Server.exe`；通过命名管道 `\\.\pipe\simple-bootstrap` 接收心跳 |
| `SystemMissionRegistry` | `SimpleLite.Bootstrap` | 单例，注册所有 SystemMission；Web-Enabled 启动时遍历 `Spawn()`；进程退出时遍历 `Stop()` |
| `ProcessHost` | `SimpleLite.Bootstrap` | 封装 `System.Diagnostics.Process` + 重定向标准输出到日志 + 退出码捕获 |
| `HeartbeatChannel` | `SimpleLite.Bootstrap` | 命名管道服务端；JSON 协议 `{ "ts", "rss", "queueDepth", "status" }`；3 个周期未达 → 标记不健康 |
| `ProcessWatchdog` | `SimpleLite.Bootstrap` | 不健康时 `Stop() + Spawn()`；指数退避 1s → 2s → 4s → 8s → 30s（上限） |
| `RunMode`（枚举） | `SimpleLite.Bootstrap` | `DesktopOnly` / `WebEnabled` |

**生命周期：**

```text
SimpleLite 启动 (Web-Enabled)
   ├─ Kestrel Up :7001/7002
   ├─ WebTerminal Up :8223
   ├─ SchedulerRuntime.Start()
   └─ SystemMissionRegistry.SpawnAll()
        └─ StartPlatformMission.Spawn()
              ├─ ProcessHost.Start("MiGu.Server.exe", args)
              ├─ HeartbeatChannel.Listen(pipeName)
              └─ Watchdog.Track(pid)

每 5s:
   HeartbeatChannel ← MiGu.Server (JSON tick)

异常:
   Watchdog 触发 → ProcessHost.Kill() → 退避等待 → Spawn() 重试
   连续 5 次失败 → 状态窗高亮 "Platform Down"，停止重试，需人工介入

SimpleLite 优雅停机:
   SystemMissionRegistry.StopAll()
   └─ StartPlatformMission.Stop()
        ├─ 发送 SIGTERM 等价（命名管道 "shutdown" 消息）
        ├─ 等待 MiGu.Server 完成 IHostedService.StopAsync (≤ 30s)
        └─ 超时则 ProcessHost.Kill()
```

**实现要点：**

- **位置**：新建 `SimpleLite/Bootstrap/` 与 `SimpleLite/RCS/SystemMissions/`。
- **不写入主库 Missions 表**：SystemMission 是进程级配置，不参与项目序列化；存储在 `simple_main.db.SystemMissionConfig`（或直接读 `simple.json`）。
- **崩溃隔离**：Platform 异常不影响 SimpleLite 调度循环；MiGu.Server 也实现 `IHostedService.StopAsync` 做 WAL Checkpoint + WS 排空 → 给 ROSE 释放磁盘。
- **多实例预防**：通过命名互斥体 + `simple.json.allowMultiple=false`（已有）确保 SimpleLite 唯一；MiGu.Server 启动时校验"父进程是否为 SimpleLite"，否则拒绝启动（防止有人手动双击 `MiGu.Server.exe`）。
- **静态资源**：MiGu.Server 用 `MapWhen + UseStaticFiles + UseSpa` 各挂一份 `index.html`。

---

## 5. 三端职责矩阵

| 维度 | SimpleLite 桌面端 | **Platform 管理端（platform-vue）** | **RCSMonitor 运营端（rcsmonitor-vue）** |
|------|---------------------|------------------------------------------|------------------------------------------|
| 地图（站点/轨道/区域）编辑 | **读写**（Desktop-Only） | **全功能读写**（Vue 地图控件内嵌SimpleLite地图） | 只读投影，不可编辑 |
| 任务编排（Mission/Recipe） | **读写** | **全功能读写**（含 Demand / Recipe） | 基础动作：暂停/取消/重派/优先级 |
| 车辆配置（参数 / 维护策略） | **读写** | **全功能读写** | 基础动作：暂停/继续/结束任务/上线/离线/手动充电等 |
| CAD 工具 | **可用** | **可用**（Vue 调用 `/api/sl/cad/*`） | 不可用 |
| 自定义字段 / 图层 | **可用** | **可用** | 只读 |
| 调度引擎（DispatchLoop） | 进程内拥有 | 远程订阅状态 + 全 API 操作 | 远程订阅状态 + 受限 API |
| 车端通信 | 拥有 | 不直连，只看投影 | 不直连，只看投影 |
| 3D 视口 | 本地 OpenGL（CycleGUI 原生） | **嵌入 SimpleLite webVRender**（全功能交互） | **嵌入 SimpleLite webVRender**（只读 + 圈选） |
| 系统级配置 | 局部（Desktop-Only） | **全局编辑 + 下发** | 不可编辑 |
| 外部对接（MES/WMS/RCS） | 不涉及 | **唯一入口** | 不涉及 |
| 路径规划/交通/充电策略 | 算法 + 调试 | **可视化编辑 + 下发** | 只读 |
| 权限/角色管理 | 本地用户表（启动登录用） | **统一管理（主源）** | 仅查看自身权限 |
| 库位 / 出入库 | 地图层（库位几何） | **业务主体 + 库存** | 监控视图（按权限） |
| 调度回放 / 日志 | 短期内存 | **长期归档 + 检索** | 故障快照 + 备注 |
| 自定义控件管理 | 本地配置 | **设计 + 发布** | 接收推送 + 按权限渲染 |

> 两个前端共用同一个 MiGu.Server 后端，区别在登录时申请的 `scope`（`Platform` vs `RCSMonitor`）与对应角色绑定的权限码 / WidgetGrant。

### 5.1 RCSMonitor 基础动作白名单（初版）

| 操作 | 权限码 | 影响范围 | 二次确认 |
|------|--------|----------|---------|
| 暂停车辆 | `ops.car.pause` | 单车 | 否 |
| 恢复车辆 | `ops.car.resume` | 单车 | 否 |
| 回原点 | `ops.car.gohome` | 单车 | 是 |
| 重置车辆会话 | `ops.car.resetSession` | 单车 | 是 |
| 手动充电 | `ops.car.manualCharge` | 单车 | 否 |
| 暂停任务 | `ops.task.pause` | 单任务 | 否 |
| 取消任务 | `ops.task.cancel` | 单任务 | 是 |
| 重派任务 | `ops.task.reassign` | 单任务 | 是 |
| 提升优先级 | `ops.task.boostPriority` | 单任务 | 否 |
| 写运营备注 | `monitor.note.write` | 标注层（写 platform.db） | 否 |

> **限权双保险**：① 浏览器侧按 `allowedOps` 隐藏按钮；② MiGu.Server YARP 中间件在转发前再次校验。`scope=RCSMonitor` 的请求路径必须落在 `/api/sl/ops/*` 白名单前缀内，否则 403。

### 5.2 Platform 管理端设计权限示例（全功能套壳）

| 操作 | 权限码 | 控件位置（platform-vue） |
|------|--------|---------------------------|
| 创建/编辑站点 | `map.site.write` | 地图设计页 · 工具栏 |
| 创建/编辑轨道（含曲线） | `map.track.write` | 地图设计页 · 工具栏 |
| 编辑车辆参数 | `vehicle.config.write` | 车辆配置页 |
| 创建/编辑 Mission | `mission.write` | 任务编排页 |
| 加载/保存项目 | `project.write` | 顶栏 |
| 触发 CAD 工具 | `cad.tool.run` | CAD 工具栏 |
| 配置中心编辑 | `config.<section>.write` | 配置中心各分页 |
| 用户/角色管理 | `auth.user.write` / `auth.role.write` | 系统管理页 |
| 切换运行模式（远程） | `system.runmode.reset` | 系统管理页 → 危险操作 |

### 5.3 Platform 平台能力补充（设备统一接入与管理）

Platform 内置通用设备管理模块（`DeviceHub`），作为所有外围设备的统一接入层与运维入口，覆盖注册、配置、状态监控、告警与审计。

**内置接入设备类型：**

- 电梯、卷帘门、安全门  
- 充电桩（自动对接协议）  
- 无线 AP、网络交换机  
- 视频摄像头、读码器、PLC

**架构原则（一次适配，后续复用）：**

- **驱动式插件架构**：设备能力抽象为 `IDeviceDriver` + `IDeviceAdapter`，每类设备只需完成一次驱动适配。  
- **协议标准化**：统一抽象 Modbus-TCP、OPC-UA、HTTP/REST、MQTT、ONVIF、私有 TCP 等协议。  
- **配置驱动上线**：新增同类设备无需改代码，只需在平台配置中心新增设备实例配置并绑定已有驱动。  
- **可观测性统一**：设备状态统一汇总到 `DeviceRuntimeStatus`（在线/离线、延迟、错误码、最近心跳、告警级别）。  
- **故障隔离**：单设备驱动异常不影响其他设备与调度主链路，驱动实例按租户/站点隔离。

### 5.4 Platform 平台能力补充（机器人群组与车队全生命周期管理）

Platform 提供车队级运维能力，支持 AGV 分区域、跨楼层、多车协作调度。

**核心能力：**

- **群组维度管理**：车队按楼层/区域/业务线分组，支持跨组协同任务。  
- **硬件健康监控**：主控、驱动器、传感器、电池、定位模块的实时状态与趋势。  
- **网络连通诊断**：链路质量、丢包、时延、断连重连次数、AP 切换质量。  
- **OTA 升级**：远程固件/软件灰度发布、分批升级、回滚策略与版本基线管理。  
- **批量操作**：休眠、唤醒、上线、下线、急停复位、一键任务清空/重派。  
- **全生命周期闭环**：入网注册 → 运行监控 → 故障工单 → 维护保养 → 退役归档。

### 5.5 Platform 平台能力补充（业务场景模板化与可扩展机制）

Platform 将典型业务场景抽象为标准模板，支持开箱即用和后续扩展。

**内置模板（首批）：**

- SPS 物料配送场景  
- 电池 Pack 自动化产线场景  
- 环线运行场景  
- 点对点柔性搬运场景

**模板内容固化：**

- 调试参数（设备、车辆、节拍、阈值）  
- 路径策略（寻路算法、权重、区域限制）  
- 交通管制规则（路口互斥、让行策略）  
- 任务流（任务编排、优先级、异常分支）

**扩展机制：**

- **配置扩展**：通过模板 DSL / JSON 配置新增场景，无需代码发布。  
- **低代码扩展**：通过可视化编排器拼接任务流与策略块。  
- **模板版本化**：模板支持版本、灰度、回滚、租户差异化覆盖。  
- **模板市场化**：支持插件包导入导出（模板 + 设备驱动 + 参数基线）。

---

## 6. 共享内核分层

```mermaid
flowchart TB
    subgraph 顶层["顶层（按端隔离）"]
        L1A["SimpleLite (CycleGUI + WebAPI Host)"]
        L1B["MiGu.Server (ASP.NET Core + YARP)"]
        L1B2["platform-vue (SPA, 管理员)"]
        L1B3["rcsmonitor-vue (SPA, 运营)"]
    end

    subgraph 共享["共享业务层 (新增)"]
        L2A["SimpleShared.Contracts<br/>(REST DTO + Swagger + WS 事件)"]
        L2B["SimpleShared.Auth<br/>(JWT + RBAC + 权限码表)"]
        L2C["SimpleShared.Config<br/>(配置模型 + 校验 + 下发协议)"]
        L2D["SimpleShared.Persistence<br/>(EF Core + SQLite + 迁移)"]
        L2E["SimpleShared.OpsCommand<br/>(运维命令白名单 + 审计 + 幂等)"]
        L2F["SimpleShared.WebApiHost<br/>(Kestrel + Auth + Swagger 公共启动器)"]
    end

    subgraph 引擎["引擎与领域 (现有)"]
        L3A["SimpleScheduler<br/>(DispatchLoop / Constraint / Recipe)"]
        L3B["SimpleCore<br/>(站点 / 轨道 / Prop / Mission)"]
        L3C["HttpClientHelper"]
        L3D["Plugins (插件 DLL)"]
    end

    L1B2 -- "/admin/* + REST + WSS" --> L1B
    L1B3 -- "/monitor/* + REST + WSS<br/>(scope=RCSMonitor)" --> L1B

    L1A --> L2A
    L1B --> L2A
    L1A --> L2B
    L1B --> L2B
    L1A --> L2C
    L1B --> L2C
    L1A --> L2D
    L1B --> L2D
    L1A --> L2E
    L1B --> L2E
    L1A --> L2F
    L1B --> L2F

    L2C --> L2D
    L2B --> L2D

    L1A --> L3A
    L1A --> L3B
    L1A --> L3D
    L1B --> L3B
    L1B --> L3C
    L3A --> L3B
```

### 新工程建议

| 工程 | 类型 | 关键职责 |
|------|------|----------|
| `SimpleShared.Contracts` | netstandard2.1 | REST DTO（POCO + DataAnnotations）+ OpenAPI/Swagger + WS 事件结构 + webVRender 桥接消息 |
| `SimpleShared.Auth` | net8.0 | IUserStore / IRoleStore / JwtIssuer / IPermissionEvaluator / 权限码表 / WidgetGrant |
| `SimpleShared.Config` | net8.0 | 强类型配置树 + 版本号 + Diff/校验 + 下发器 |
| `SimpleShared.Persistence` | net8.0 | EF Core 8 多 Provider 抽象（**SQLite / MySQL / PostgreSQL / SQL Server**）+ 迁移 + `DbProviderOptions` + 连接串构建器 + `WalSqliteOptions`（仅 SQLite） |
| `SimpleShared.OpsCommand` | net8.0 | 运维白名单命令、审计、幂等键、频次限流 |
| `SimpleShared.WebApiHost` | net8.0 | Kestrel 公共启动器：JWT 中间件 / Swagger / CORS / 健康检查 / 请求审计 |
| `MiGu.Server` | net8.0 ASP.NET Core | 业务 BFF + **YARP 反代 SimpleLite** + 静态托管两份 Vue dist；**启动时校验父进程为 SimpleLite，否则拒绝运行**（防误用） |
| `platform-vue` | Vue 3 + Vite + Pinia | 全功能套壳：复刻 SimpleLite 所有控件 |
| `rcsmonitor-vue` | Vue 3 + Vite + Pinia | 运营监控：按权限渲染，运维动作面板 |
| `packages/sl-controls`（pnpm workspace） | Vue 3 组件库 | Workspace3D（嵌 webVRender）/ 地图列表 / 任务表 / CAD 工具栏等共享组件 |

### 6.1 Platform Vue 控件复刻清单（与 SimpleLite CycleGUI 对照）

| SimpleLite CycleGUI 面板 | Vue 组件（位于 `sl-controls`） | 备注 |
|--------------------------|--------------------------------|------|
| 主菜单栏 / 工具栏 | `<AppShell>` 顶栏 + 侧栏 | platform-vue 全功能；rcsmonitor-vue 仅显示运营菜单 |
| Workspace 3D 视口 | `<Workspace3D>` | **iframe / Web Component 嵌入 SimpleLite webVRender**；交互事件用 `postMessage` 桥接 |
| 地图面板（Sites / Tracks） | `<MapEditor>` + `<TrackTable>` | 表格 + 拓扑视图 |
| Car 面板 | `<CarPanel>` | 表格 + 表单 |
| Mission 面板 | `<MissionEditor>` | 任务流图 + 表单 |
| CAD 工具栏 | `<CadToolbar>` | 工具按钮组（按 `cad.tool.run` 显隐） |
| 字段编辑 / 图层 | `<FieldsLayers>` | 表单 + 树 |
| 状态 / 诊断 | `<StatesDashboard>` | ECharts 实时图 |
| 文件对话框 | `<ProjectFileDialog>` | 文件浏览器 + REST 上传/下载 |
| 运维动作面板 | `<OpsActionPanel>` | RCSMonitor 主战场，按 §5.1 白名单生成按钮 |

> 复刻策略：**先 1:1 对齐功能**，UI 风格交给前端工程师二次设计；接口协议统一在 `SimpleShared.Contracts` 内。

### 6.2 webVRender 嵌入方案

CycleGUI 的 `WebTerminal.Use(port, ico)` 已经原地提供：
- WebSocket 路由（驱动 Workspace 同步）
- 嵌入式 webVRender 页面（HTML + JS + WASM）

Vue 端集成方式（推荐 iframe，最简单稳定）：

```vue
<!-- packages/sl-controls/src/Workspace3D.vue (简化示意) -->
<template>
  <iframe
    ref="frame"
    :src="vrUrl"
    class="workspace-3d"
    @load="onReady" />
</template>

<script setup lang="ts">
import { computed, ref } from 'vue';
const props = defineProps<{
  host: string;        // e.g. host:8223
  scope: 'Platform' | 'RCSMonitor';
  token: string;       // 透传 JWT
  readOnly?: boolean;
}>();
const emit = defineEmits<{
  (e: 'pick', wp: { x: number; y: number }): void;
  (e: 'select', names: string[]): void;
}>();
const frame = ref<HTMLIFrameElement>();
const vrUrl = computed(() =>
  `http://${props.host}/?scope=${props.scope}&token=${encodeURIComponent(props.token)}&ro=${props.readOnly ? 1 : 0}`);
function onReady() {
  window.addEventListener('message', (ev) => {
    if (ev.source !== frame.value?.contentWindow) return;
    const msg = ev.data;
    if (msg.type === 'workspace.pick') emit('pick', msg.payload);
    else if (msg.type === 'workspace.select') emit('select', msg.payload);
  });
}
</script>
```

`SimpleLite/Rendering/SimpleSceneRenderer.cs` 端按 `scope` 和 `ro` 控制：
- `scope=RCSMonitor` 或 `ro=1` → 禁用编辑工具（不响应 `SelectObject`/`GetPosition` 中的拖动）
- 通过 `postMessage` 向 iframe 父页面回传选择/点击事件

如未来需要更深的双向集成（如自定义 Vue 弹层叠在 3D 视口上），可升级到 Web Component（`<sl-workspace3d>`），但 iframe 已能覆盖 95% 场景。

### 6.3 YARP 反向代理配置（示例）

```csharp
// MiGu.Server / Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
    .AddTransforms(ctx =>
    {
        // 透传当前 JWT 的 userId / scope 给 SimpleLite
        ctx.AddRequestTransform(async tc =>
        {
            var ident = tc.HttpContext.User;
            tc.ProxyRequest.Headers.Add("X-On-Behalf-Of", ident.FindFirst("sub")?.Value ?? "");
            tc.ProxyRequest.Headers.Add("X-Scope", ident.FindFirst("scope")?.Value ?? "");
            tc.ProxyRequest.Headers.Add("X-Svc-Token", SvcTokenIssuer.Current());
        });
    });

builder.Services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(opt => opt.TokenValidationParameters = JwtTokenOptions.Default);

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();

// 关键：scope=RCSMonitor 的请求只能命中 /api/sl/ops/* 白名单
app.MapReverseProxy(pipe => pipe.Use(async (ctx, next) =>
{
    var scope = ctx.User.FindFirst("scope")?.Value;
    var path = ctx.Request.Path.Value ?? "";
    if (scope == "RCSMonitor" && !path.StartsWith("/api/sl/ops/"))
    {
        ctx.Response.StatusCode = StatusCodes.Status403Forbidden;
        await ctx.Response.WriteAsync("Scope RCSMonitor cannot access this endpoint");
        return;
    }
    await next();
}));

app.UseStaticFiles();
app.MapWhen(c => c.Request.Path.StartsWithSegments("/admin"),
    sub => sub.UseStaticFiles().UseSpa(s => s.Options.SourcePath = "frontends/platform-vue/dist"));
app.MapWhen(c => c.Request.Path.StartsWithSegments("/monitor"),
    sub => sub.UseStaticFiles().UseSpa(s => s.Options.SourcePath = "frontends/rcsmonitor-vue/dist"));

app.Run();
```

`appsettings.json` 中的 YARP 路由：

```json
{
  "ReverseProxy": {
    "Routes": {
      "sl-route": {
        "ClusterId": "sl-cluster",
        "Match": { "Path": "/api/sl/{**catch-all}" },
        "Transforms": [
          { "PathRemovePrefix": "/api/sl" },
          { "RequestHeader": "Host", "Set": "" }
        ]
      }
    },
    "Clusters": {
      "sl-cluster": {
        "Destinations": {
          "sl1": { "Address": "http://127.0.0.1:7001/" }
        }
      }
    }
  }
}
```

---

## 7. 数据库与高可用（多 Provider）

只剩两个逻辑库（`simple_main` / `platform`）；持久层基于 **EF Core**，**通过 Provider 切换底层数据库**。**SQLite 是默认与边缘单机首选**，企业级或已有 IT 基础设施现场可平滑切到 **MySQL / PostgreSQL / SQL Server**；高可用方案随 Provider 不同。

### 7.1 持久层抽象（EF Core Provider 矩阵）

```mermaid
flowchart TB
    subgraph App["应用代码 (SimpleLite / MiGu.Server)"]
        DOM["领域服务 / Repository"]
        EFC["EF Core 8 DbContext"]
        OPT["DbProviderOptions<br/>{ provider, conn, ha }"]
    end

    subgraph SharedLayer["SimpleShared.Persistence"]
        BLD["ConnectionStringBuilder"]
        MIG["Migrations<br/>(SQLite/MySQL/Pg/MSSQL 各一套)"]
        DI["AddSimplePersistence(...)<br/>(Provider 注入)"]
    end

    subgraph Providers["EF Core Provider"]
        P1["Microsoft.EntityFrameworkCore.Sqlite"]
        P2["Pomelo.EntityFrameworkCore.MySql"]
        P3["Npgsql.EntityFrameworkCore.PostgreSQL"]
        P4["Microsoft.EntityFrameworkCore.SqlServer"]
    end

    DOM --> EFC
    EFC --> OPT
    OPT --> DI
    DI --> P1
    DI --> P2
    DI --> P3
    DI --> P4
    DI --> MIG
    DI --> BLD

    P1 -. file .-> S1[(SQLite 文件<br/>+ WAL)]
    P2 -. tcp .-> S2[(MySQL 8.x)]
    P3 -. tcp .-> S3[(PostgreSQL 14+)]
    P4 -. tcp .-> S4[(SQL Server 2019+)]
```

**抽象核心：**

- 所有 `DbContext`（如 `MainDbContext` / `PlatformDbContext`）**不感知 Provider**，使用通用 LINQ + 注解；少量数据库特性（如 `JSON` 列、`uuid` 主键）由 `IDbProviderSpecifics` 抽象出三套实现。
- **迁移按 Provider 独立维护**：`Migrations/Sqlite`、`Migrations/MySql`、`Migrations/Npgsql`、`Migrations/SqlServer`；CI 跑全部矩阵保证不偏漂。
- **运行期切换**：仅启动期生效，通过 `simple.json` / `Platform.appsettings.json` 的 `database.provider` 字段决定加载哪一个；不支持热切。
- **测试矩阵**：CI 用 Testcontainers 起对应 DB 跑端到端集成测试。

### 7.2 各库存储内容（与 Provider 无关）

| 逻辑库 | 拥有进程 | 主要表/数据 |
|--------|----------|-------------|
| **simple_main** | SimpleLite | Maps, Sites, Tracks, SpecialProps, Missions, Cars, Plugins, DesignAuditLog, OpsAuditLog, LocalUsers, RunModeHistory |
| **platform** | Platform | Users, Roles, RolePermissions, WidgetGrants, SystemConfig, ExternalAdapters, RoutingPolicies, VehicleMaintenancePolicies, ChargePolicies, TaskAllocationPolicies, TrafficRules, Locations, Inventory, OpsLogs（含 RCSMonitor 来源）, Annotations, Snapshots, Versions, CustomWidgets |

> 原 v1.2 中的 `rcsmonitor_local` 取消；其表（OpsLogs / Annotations / Snapshots / WidgetLayoutCache）合并到 `platform`，加 `source='RCSMonitor'` 字段区分。  
> Provider 不同时，逻辑表名一致；物理实现差异（`uuid` vs `binary(16)`、`json` vs `nvarchar(max)`、自增策略等）由迁移文件适配。

### 7.3 SQLite + ROSE HA（默认 / 边缘单机）

```mermaid
flowchart TB
    subgraph A["主节点 NODE-A (Active)"]
        SL_A["SimpleLite.exe"]
        PL_A["MiGu.Server.exe"]
        D_A[("受 ROSE 保护盘 R:\<br/>simple_main.db<br/>platform.db<br/>(WAL)")]
    end
    subgraph B["备节点 NODE-B (Standby)"]
        SL_B["SimpleLite.exe (suspended)"]
        PL_B["MiGu.Server.exe (suspended)"]
        D_B[("ROSE 镜像盘 R:\")]
    end
    VIP(("浮动 IP / VIP"))
    Client["客户端"]
    Client --> VIP --> SL_A
    A <-- "ROSE 块级镜像 + 心跳" --> B
    A -. 故障切换 .-> B
```

**适用场景**：边缘工控机 / 单机现场 / IT 基础设施薄弱 / 初装版本。

**关键约束：**

| 约束 | 落地做法 |
|------|----------|
| **数据文件必须放 ROSE 受保护盘** | 两端 `Configuration` 中数据库路径统一指向 `%SIMPLE_DATA_ROOT%`（默认 `R:\SimpleData\`） |
| **同一时刻只能一个节点写库** | ROSE 切换前后保证只有 Active 节点起服务；备节点服务进程**默认禁用自启** |
| **关闭跨进程共享缓存** | 连接串 `Cache=Private; Mode=ReadWriteCreate; Pooling=true; Default Timeout=30` |
| **支持优雅停机** | 实现 `IHostedService.StopAsync`，等 WS 排空 + Checkpoint(WAL) |
| **客户端通过 VIP 访问** | Vue 与车端均连浮动 IP；WS 自动重连 < 5s |
| **Web-Enabled 与 ROSE 强绑定** | 双机热备只在 Web-Enabled 模式下有意义 |
| **切换演练** | `tools/ha/failover-drill.ps1` |

**ROSE 资源建议命名：**

| 资源 | 类型 | 依赖 |
|------|------|------|
| `RES_DISK_R` | Mirror Disk | — |
| `RES_VIP_LAN` | Virtual IP | RES_DISK_R |
| `RES_SVC_SL` | Service: SimpleLite (Web-Enabled) | RES_DISK_R, RES_VIP_LAN |
| `RES_SVC_PL` | Service: MiGu.Server | RES_DISK_R, RES_VIP_LAN, RES_SVC_SL |
| `RES_SCRIPT_CHK` | 数据库健康检查脚本 | RES_DISK_R |

**RTO / RPO**：RTO < 60s，RPO ≈ 0（块级镜像）。

### 7.4 MySQL + InnoDB Cluster / MGR

```mermaid
flowchart TB
    subgraph App["应用层 (VIP + 重试)"]
        SL["SimpleLite.exe"]
        PL["MiGu.Server.exe"]
    end
    subgraph Router["MySQL Router (或 ProxySQL)"]
        R1["VIP :6446 (RW)"]
        R2["VIP :6447 (RO)"]
    end
    subgraph Cluster["InnoDB Cluster (MGR, group_replication)"]
        M1[("Primary<br/>node1")]
        M2[("Secondary<br/>node2")]
        M3[("Secondary<br/>node3")]
        M1 <-- "Group Replication" --> M2
        M2 <-- "Group Replication" --> M3
        M1 <-- "Group Replication" --> M3
    end
    SL --> R1
    PL --> R1
    R1 --> M1
    R2 --> M2
    R2 --> M3
```

**适用场景**：现场已有 MySQL DBA / 中等规模 / Linux 优先 / 多读副本需求。

**关键说明：**

- **EF Core Provider**：`Pomelo.EntityFrameworkCore.MySql`（对 MySQL 8.x / MariaDB 10.x 兼容性最好）。
- **HA 形态**：推荐 **InnoDB Cluster（基于 MySQL Group Replication + MySQL Router）** 三节点，单点故障自动重选主；老版本 MySQL 可降级用 **MHA / Orchestrator + 半同步复制**。
- **连接配置**：应用连 MySQL Router 的 RW 端口（`:6446`），由 Router 自动路由到当前 Primary；只读分析查询可走 RO 端口（`:6447`）。
- **字符集**：统一 `utf8mb4` + `utf8mb4_0900_ai_ci`；EF Core 配 `CharSet.Utf8Mb4`。
- **写入隔离级别**：`READ COMMITTED`（避免 RR 下的间隙锁导致死锁）；MGR 要求 InnoDB 引擎、主键必填。
- **审计/慢日志**：开 `general_log` + `slow_query_log`；MiGu.Server 启动期校验。
- **备份**：每天 `mysqldump --single-transaction` 或 XtraBackup 到 NAS；保留 30 天 + Binlog。
- **RTO / RPO**：RTO ≈ 10–30s（MGR 自动选主）；RPO ≈ 0（半同步 / Group Replication 强一致）。

### 7.5 PostgreSQL + Patroni / 流复制

```mermaid
flowchart TB
    subgraph App["应用层"]
        SL["SimpleLite.exe"]
        PL["MiGu.Server.exe"]
    end
    subgraph LB["HAProxy / PgBouncer"]
        H1["VIP :5432 (RW → leader)"]
        H2["VIP :5433 (RO → replicas)"]
    end
    subgraph Cluster["Patroni 集群"]
        P1[("Leader<br/>pg1")]
        P2[("Replica<br/>pg2")]
        P3[("Replica<br/>pg3")]
        DCS[("DCS<br/>etcd / Consul / ZooKeeper")]
        P1 -- "流复制" --> P2
        P1 -- "流复制" --> P3
        P1 <-- "leader lease" --> DCS
        P2 <-- "heartbeat" --> DCS
        P3 <-- "heartbeat" --> DCS
    end
    SL --> H1
    PL --> H1
    H1 --> P1
    H2 --> P2
    H2 --> P3
```

**适用场景**：复杂查询 / GIS（PostGIS）/ JSON 重场景 / 已有 Postgres DBA / 长期数据归档与分析。

**关键说明：**

- **EF Core Provider**：`Npgsql.EntityFrameworkCore.PostgreSQL`；可直接使用 `uuid` / `jsonb` / `tstzrange` 等原生类型。
- **HA 形态**：推荐 **Patroni + etcd（或 Consul）+ 流复制**；HAProxy / PgBouncer 提供单一 RW VIP。
- **同步策略**：`synchronous_commit = remote_apply` + `synchronous_standby_names = 'ANY 1 (pg2,pg3)'`，写至少一个备机确认，兼顾性能与 RPO≈0。
- **PgBouncer**：建议事务级（`pool_mode=transaction`），MiGu.Server 并发连接通过 PgBouncer 复用；注意 EF Core 显式事务跨多个语句时不要踩 transaction 模式陷阱。
- **JSONB 利用**：`SystemConfig` / `CustomWidget.SchemaJson` 等列直接用 `jsonb` + GIN 索引，比 SQLite 的 TEXT/JSON 检索强很多。
- **备份**：`pg_basebackup` + WAL 归档（`archive_command` → NAS / S3 / pgBackRest）。
- **RTO / RPO**：RTO ≈ 10–30s（Patroni 自动 failover）；RPO ≈ 0（同步流复制）。

### 7.6 SQL Server + Always On Availability Groups

```mermaid
flowchart TB
    subgraph App["应用层"]
        SL["SimpleLite.exe"]
        PL["MiGu.Server.exe"]
    end
    subgraph Listener["AG Listener (DNS + VIP)"]
        L1["VIP :1433 (RW)"]
        L2["ReadOnly Routing"]
    end
    subgraph Cluster["WSFC + Always On AG"]
        AG1[("Primary<br/>sql1")]
        AG2[("Secondary<br/>sql2 同步提交")]
        AG3[("Secondary<br/>sql3 异步提交/可读")]
        AG1 -- "同步提交" --> AG2
        AG1 -- "异步提交" --> AG3
        WSFC[/"Windows Server Failover<br/>Cluster (Quorum)"/]
        AG1 --- WSFC
        AG2 --- WSFC
        AG3 --- WSFC
    end
    SL --> L1
    PL --> L1
    L2 --> AG3
```

**适用场景**：Windows 工控/服务器场景 / 已有 SQL Server 许可与 DBA / 与企业 AD/SSO 集成。

**关键说明：**

- **EF Core Provider**：`Microsoft.EntityFrameworkCore.SqlServer`；支持 SQL Server 2019+（建议 Enterprise 版以启用同步提交副本数 ≥3 + Read-Only Routing）。Standard 版可降级为 2 副本基本可用性组。
- **HA 形态**：**WSFC（Windows Server Failover Cluster）+ Always On Availability Groups**；通过 **AG Listener** 暴露统一虚拟名/VIP，客户端连 Listener 名即可。
- **同步策略**：核心库（`platform` / `simple_main`）配 1 个同步提交副本（RPO=0），1–N 个异步副本（可读分析）。
- **认证**：建议混合身份认证；MiGu.Server 用 SQL Login，SimpleLite 桌面端可走 Windows 集成认证。
- **TempDB**：每节点分摊；MultipleActiveResultSets（MARS）建议关闭，EF Core 已能避免。
- **备份**：`BACKUP DATABASE ... WITH COMPRESSION` + 事务日志备份每 15min；保留策略与公司 IT 一致。
- **RTO / RPO**：RTO ≈ 10–30s（AG 自动 failover）；RPO ≈ 0（同步提交副本）。

### 7.7 选型矩阵

| 维度 | SQLite + ROSE | MySQL InnoDB Cluster | PostgreSQL Patroni | SQL Server Always On |
|------|---------------|----------------------|---------------------|----------------------|
| **典型现场** | 边缘工控机 / 单机 | 中型现场 / Linux 优先 / 已有 MySQL DBA | 复杂分析 / GIS / 已有 PG DBA | Windows 企业环境 / 已有 SQL Server |
| **并发写吞吐** | 低（千级 TPS） | 高（万级） | 高（万级） | 高（万级） |
| **节点数** | 2（主备） | 3+（推荐 3） | 3+ | 2–3（含见证或共享磁盘见证） |
| **复制粒度** | 块级磁盘镜像（ROSE） | Group Replication 行级 | WAL 流复制 | 同步/异步提交 |
| **RTO** | < 60s | 10–30s | 10–30s | 10–30s |
| **RPO** | ≈0（块级实时） | ≈0（强一致） | ≈0（同步） | ≈0（同步提交副本） |
| **运维复杂度** | 低（ROSE 包办） | 中（要会 MGR）| 中–高（要会 Patroni + DCS） | 中（要熟 WSFC） |
| **跨机房 / 多活** | 不支持 | 支持（多组复制 + 路由） | 支持（流复制多机房） | 支持（分布式 AG） |
| **额外依赖** | ROSE HA 软件 | MySQL Router / ProxySQL | etcd/Consul + HAProxy/PgBouncer | Windows Server + WSFC + AD |
| **License 成本** | 仅 ROSE 授权 | 开源（社区版） / 商业支持可选 | 开源 | SQL Server License（Enterprise 较贵） |
| **JSON / 复杂查询** | 弱（TEXT/JSON1）| 中（5.7+ JSON） | **强（jsonb + GIN）** | 中（NVARCHAR + JSON_VALUE） |
| **GIS** | 弱（SpatiaLite） | 中 | **强（PostGIS）** | 强（Spatial） |

> **现场决策建议**：默认提供 SQLite 版本（开箱即用 + ROSE 双机）。客户已有数据库基础设施时，按团队最熟悉的栈选 MySQL / PostgreSQL / SQL Server；产品仅维护 4 套迁移与一份连接配置规范。

### 7.8 配置示例（`simple.json` / `appsettings.json`）

#### 7.8.1 SQLite（默认）

```json
{
  "database": {
    "provider": "Sqlite",
    "simple_main": {
      "dataSource": "%SIMPLE_DATA_ROOT%/simple_main.db",
      "extra": "Cache=Private;Mode=ReadWriteCreate;Pooling=true;Default Timeout=30"
    },
    "platform": {
      "dataSource": "%SIMPLE_DATA_ROOT%/platform.db",
      "extra": "Cache=Private;Mode=ReadWriteCreate;Pooling=true;Default Timeout=30"
    },
    "ha": { "mode": "ROSE", "protectedDisk": "R:\\SimpleData" }
  }
}
```

#### 7.8.2 MySQL

```json
{
  "database": {
    "provider": "MySql",
    "simple_main": {
      "host": "rcs-mysql.lan",
      "port": 6446,
      "database": "simple_main",
      "user": "simple_app",
      "password": "${SECRET_MYSQL_PWD}",
      "extra": "SslMode=Required;CharSet=utf8mb4;DefaultCommandTimeout=30"
    },
    "platform": {
      "host": "rcs-mysql.lan",
      "port": 6446,
      "database": "simple_platform",
      "user": "simple_app",
      "password": "${SECRET_MYSQL_PWD}"
    },
    "ha": { "mode": "InnoDBCluster", "router": "rcs-mysql.lan:6446" }
  }
}
```

#### 7.8.3 PostgreSQL

```json
{
  "database": {
    "provider": "Npgsql",
    "simple_main": {
      "host": "rcs-pg.lan",
      "port": 5432,
      "database": "simple_main",
      "user": "simple_app",
      "password": "${SECRET_PG_PWD}",
      "extra": "Ssl Mode=Require;Pooling=true;Maximum Pool Size=80;Command Timeout=30"
    },
    "platform": {
      "host": "rcs-pg.lan",
      "port": 5432,
      "database": "simple_platform",
      "user": "simple_app",
      "password": "${SECRET_PG_PWD}"
    },
    "ha": { "mode": "Patroni", "vip": "rcs-pg.lan", "readReplicaPort": 5433 }
  }
}
```

#### 7.8.4 SQL Server

```json
{
  "database": {
    "provider": "SqlServer",
    "simple_main": {
      "server": "tcp:rcs-ag.lan,1433",
      "database": "simple_main",
      "user": "simple_app",
      "password": "${SECRET_MSSQL_PWD}",
      "extra": "Encrypt=True;TrustServerCertificate=False;MultiSubnetFailover=True;Application Name=SimpleLite"
    },
    "platform": {
      "server": "tcp:rcs-ag.lan,1433",
      "database": "simple_platform",
      "user": "simple_app",
      "password": "${SECRET_MSSQL_PWD}",
      "extra": "Encrypt=True;TrustServerCertificate=False;MultiSubnetFailover=True"
    },
    "ha": { "mode": "AlwaysOnAG", "listener": "rcs-ag.lan" }
  }
}
```

> **密码注入**：`${SECRET_*}` 由 `IConfiguration` 的环境变量 / Azure Key Vault / DPAPI 加密文件提供；明文绝不入仓库。

### 7.9 跨 Provider 迁移与数据搬迁

- **首次部署切换**：通过 `tools/db/migrate.ps1 --from=Sqlite --to=Npgsql` 一键导出/导入；底层使用 EF Core `IModel` 反序列化每张表后批量写入目标。
- **滚动升级**：不支持热切；停服窗口内执行迁移；保留旧 SQLite 文件作回退包。
- **CI 守护**：每个迁移 PR 必须通过四套 Provider 的迁移 + 端到端测试（Testcontainers）。
- **数据类型差异**：UUID（SQLite TEXT / MySQL CHAR(36) / Pg uuid / MSSQL UNIQUEIDENTIFIER）、JSON（SQLite TEXT JSON1 / MySQL JSON / Pg jsonb / MSSQL NVARCHAR JSON）由 `IDbProviderSpecifics` 抽出三套配置；应用层无感知。

---

## 8. 用户 / 权限模型（含控件级权限）

```mermaid
classDiagram
    class User {
        +Guid Id
        +string Username
        +string PasswordHash
        +string Email
        +bool Enabled
        +DateTime LastLogin
    }
    class Role {
        +Guid Id
        +string Name
        +string Scope
    }
    class Permission {
        +string Code
        +string Resource
    }
    class WidgetGrant {
        +string WidgetId
        +string Visibility
    }
    class Tenant {
        +Guid Id
        +string Name
    }
    User "1" --> "*" Role : assigned
    Role "1" --> "*" Permission : grants
    Role "1" --> "*" WidgetGrant : grants
    Tenant "1" --> "*" User
    User -- LoginSession
    LoginSession : +string JwtId
    LoginSession : +DateTime IssuedAt
    LoginSession : +string ClientApp
    LoginSession : +string Scope
```

**落地四件套：**

1. **认证**：`SimpleShared.Auth` 提供 `JwtIssuer`；Web-Enabled 时 MiGu.Server 签发；Desktop-Only 时 SimpleLite 本地签发短期 Token（24h）。
2. **授权**：所有 WebAPI + WS 调用走 `IPermissionEvaluator`；权限码 `<area>.<action>`。
3. **范围（Scope）**：`Lite` / `Platform` / `RCSMonitor` / `*`；同一用户在不同端可用集合不同。Vue 端登录时由前端代码根据访问路径自动带入 `scope`（`/admin/*` → `Platform`，`/monitor/*` → `RCSMonitor`）。
4. **控件级权限**：除 `Permission` 外，角色还可关联 `WidgetGrant`，每个 `WidgetId` 三档可见性：
   - `hidden`：根本不渲染
   - `readonly`：渲染但禁用交互
   - `interactive`：完全可交互（仍受操作权限码二次校验）

### 8.1 RCSMonitor 登录与权限拉取

```mermaid
sequenceDiagram
    participant U as 运营用户
    participant RV as rcsmonitor-vue
    participant P as MiGu.Server
    participant L as SimpleLite (YARP 后侧)
    participant DBp as platform.db

    U->>RV: 访问 https://host:8080/monitor
    RV->>P: GET /monitor/index.html (静态)
    P-->>RV: 200 OK
    U->>RV: 输入账号密码
    RV->>P: POST /api/auth/login {scope=RCSMonitor}
    P->>P: 校验账号 + 计算 EffectivePermissions
    P->>DBp: 写 LoginSession
    P-->>RV: { token, user, effectivePermissions }
    RV->>RV: 按 visibleWidgets / allowedOps 裁剪 UI
    RV->>P: GET /api/sl/projection/map (token, scope=RCSMonitor)
    P->>P: YARP 中间件: scope 合法? path 在 /ops/* 之外? 投影类不拦截
    P->>L: GET /api/projection/map (X-On-Behalf-Of, X-Scope, X-Svc-Token)
    L-->>P: 投影
    P-->>RV: 投影
    RV->>P: WS /ws/events (token)
    P->>L: WS /ws/events (svc identity)
    L-->>P: 推送
    P-->>RV: 转发
```

---

## 9. 平台配置中心

覆盖以下维度：

| 配置维度 | 说明 |
|----------|------|
| 系统级配置 | 运行参数、日志策略、安全策略 |
| 外部系统对接 | MES/WMS/RCS 等标准接口配置 |
| 路径规划策略 | 算法选择、权重、避障规则、区域限速 |
| 车辆维护策略 | 电量阈值、故障上报、自动报修 |
| 充电逻辑 | 充电优先级、空闲充电、任务中断充电 |
| 任务分配机制 | 负载均衡、就近分配、优先级调度 |
| 交通管制规则 | 路口策略、区域互斥、动态让行 |
| 权限与角色管理 | 多用户、功能权限控制、控件授权 |
| 第三方设备统一接入与管理 | 电梯/门禁/充电桩/AP/交换机/摄像头/读码器/PLC 统一注册、配置、监控、告警与审计 |
| 机器人群组与车队全生命周期管理 | 分区域/跨楼层/多车协作；硬件监控、网络诊断、OTA、批量操作、维护闭环 |
| 业务场景模板化与扩展机制 | SPS、Pack 产线、环线、点对点模板；参数/路径/交管/任务流固化；配置/低代码扩展 |
| 库位管理 | 出入库管理、库存管理、库位可视化 |
| 运营维护 | 调度回放、日志管理、版本维护 |
| 自定义控件管理 | 呼叫/展示界面可自由定义（platform-vue + rcsmonitor-vue 双渲染器） |

```mermaid
flowchart LR
    subgraph PlatformVue["platform-vue 配置中心"]
        UI1[系统级]
        UI2[外部对接]
        UI3[路径规划]
        UI4[车辆维护]
        UI5[充电]
        UI6[任务分配]
        UI7[交通管制]
        UI8[权限/角色/控件]
        UI9[库位/库存]
        UI10[运营/回放]
        UI11[自定义控件]
    end

    subgraph CC["ConfigCenter (MiGu.Server)"]
        Sch[Schema 注册表]
        Ver[版本/审计]
        Val[校验器]
        Pub[发布器]
    end

    UI1 --> Sch
    UI2 --> Sch
    UI3 --> Sch
    UI4 --> Sch
    UI5 --> Sch
    UI6 --> Sch
    UI7 --> Sch
    UI8 --> Sch
    UI9 --> Sch
    UI10 --> Sch
    UI11 --> Sch
    Sch --> Val --> Ver --> Pub

    Pub -- "REST PUT /api/sl/config/{section} (via YARP)" --> SL["SimpleLite (主服务)"]
    Pub -- "WS broadcast: config.updated" --> RMVue["rcsmonitor-vue"]
    Pub -- "WS broadcast: config.updated" --> AdminVue["其他在线 platform-vue"]
```

### 配置强类型骨架（C# 示例）

```csharp
public record SystemConfig(int DispatchLoopHz, LogPolicy Log, SecurityPolicy Security);

public record ExternalIntegrations(List<MesEndpoint> Mes, List<WmsEndpoint> Wms, List<RcsEndpoint> Rcs);

public record RoutingPolicy(
    string Algorithm,
    Dictionary<string, double> Weights,
    List<AvoidanceRule> Avoidance,
    List<ZoneSpeedLimit> ZoneSpeedLimits);

public record VehicleMaintenancePolicy(
    double LowBatteryThreshold,
    double CriticalBatteryThreshold,
    FaultReportPolicy FaultReport,
    AutoRepairPolicy AutoRepair);

public record ChargePolicy(bool AllowMidTaskCharge, double IdleChargeAfterSec, List<ChargePriorityRule> Priority);

public record TaskAllocationPolicy(AllocationMode Mode, bool LoadBalance, int MaxQueuePerCar);

public record TrafficRule(List<IntersectionPolicy> Intersections, List<ZoneMutex> Mutex, List<DynamicYield> Yields);

public record DeviceManagementConfig(
    List<DeviceDriverBinding> Drivers,
    List<DeviceInstance> Devices,
    DeviceHealthPolicy HealthPolicy,
    AlarmPolicy AlarmPolicy);

public record FleetLifecycleConfig(
    List<FleetGroup> Groups,
    OtaPolicy Ota,
    BatchOpsPolicy BatchOps,
    NetworkDiagPolicy NetworkDiag);

public record ScenarioTemplateConfig(
    List<ScenarioTemplate> Templates,
    TemplateDslPolicy DslPolicy,
    LowCodePolicy LowCode,
    TemplateVersionPolicy VersionPolicy);

public record LocationManagement(List<Location> Locations, List<InventoryRule> InventoryRules);

public record OpsConfig(PlaybackPolicy Playback, LogRetention LogRetention, VersionPolicy Version);

public record CustomWidget(string Id, string Name, string SchemaJson, string LayoutJson, List<string> BindToScopes);

public record EffectivePermissions(
    string UserId,
    int Version,
    List<string> AllowedOps,
    List<WidgetGrantDto> VisibleWidgets);
```

**发布机制：** Schema → 校验 → 版本 → 灰度 → 全量；MiGu.Server 通过 YARP `PUT /api/sl/config/{section}` 推到 SimpleLite，主服务原子切换 + ack；失败自动回滚，WS `config.rollback` 广播。

---

## 10. 关键交互序列

### 10.1 启动登录 + Web-Enabled 三端建链

```mermaid
sequenceDiagram
    participant U as 用户
    participant L as SimpleLite (CycleGUI)
    participant BL as BootLoginPanel
    participant K as Kestrel (WebAPI)
    participant P as MiGu.Server (YARP)
    participant V as platform-vue
    participant RV as rcsmonitor-vue

    U->>L: 启动 SimpleLite.exe
    L->>L: 读取 simple.json
    alt rememberRunMode = true
        L->>L: 直接采用 runMode (仍鉴权)
    else
        L->>BL: 弹出登录窗
        U->>BL: 输入凭据 + 选 Web-Enabled (+记住选择)
        BL->>L: 写 simple.json (runMode, rememberRunMode)
    end
    L->>L: 切换 CycleGUI 到"服务状态窗"
    L->>K: 启动 Kestrel :7001/7002 + WebTerminal :8223
    L->>L: SchedulerRuntime.Start()
    L->>P: spawn MiGu.Server.exe
    P->>P: Kestrel :8080/8081 Up
    P->>P: YARP 加载路由
    P->>K: POST /api/internal/handshake (svcToken)

    Note over U,RV: 管理员登录
    U->>V: 访问 https://host:8080/admin
    V->>P: POST /api/auth/login {scope=Platform}
    P-->>V: { token, effectivePermissions }
    V->>P: GET /api/sl/projection/map
    P->>K: GET /api/projection/map (YARP 转发 + X-On-Behalf-Of)
    K-->>P: 投影
    P-->>V: 投影
    V-->>V: Workspace3D iframe 加载 http://host:8223?scope=Platform&token=...

    Note over U,RV: 运营人员登录
    U->>RV: 访问 https://host:8080/monitor
    RV->>P: POST /api/auth/login {scope=RCSMonitor}
    P-->>RV: { token, effectivePermissions (受限) }
    RV->>RV: 按 allowedOps/visibleWidgets 渲染
```

### 10.2 Desktop-Only 启动（对比）

```mermaid
sequenceDiagram
    participant U as 用户
    participant L as SimpleLite
    participant BL as BootLoginPanel

    U->>L: 启动 SimpleLite.exe
    L->>L: 读 simple.json (无记忆 或 选项=DesktopOnly)
    L->>BL: 必要时弹出登录窗
    U->>BL: 输入凭据 + 选 Desktop-Only
    BL->>L: 验证通过
    L->>L: 启动 CycleGUI 全功能 UI
    L->>L: SchedulerRuntime.Start()
    Note over L: 不启动 Kestrel<br/>不启动 WebTerminal<br/>不 spawn Platform
    L-->>U: 进入设计端主界面
```

### 10.3 platform-vue 编辑地图站点 → SimpleLite 落库

```mermaid
sequenceDiagram
    participant V as platform-vue
    participant P as MiGu.Server (YARP)
    participant L as SimpleLite (WebAPI)
    participant DBl as simple_main.db
    participant RV as rcsmonitor-vue (订阅)

    V->>P: POST /api/sl/map/site {x, y, name}
    P->>P: JWT + 鉴权 (map.site.write, scope=Platform)
    P->>L: POST /api/map/site (YARP 转发 + X-On-Behalf-Of)
    L->>L: 校验 + SimpleLib.SetSite()
    L->>DBl: 写入 + DesignAuditLog
    L-->>P: 201 Created { siteId }
    P-->>V: 201 + siteId
    L->>L: WS broadcast { type: "map.site.created", payload }
    L-->>P: WS event
    P-->>V: WS event (前端 Workspace3D iframe 收到 SimpleLite 推送的 PutModelObject 同步)
    P-->>RV: WS event (RCSMonitor 接收并按权限展示)
```

### 10.4 平台编辑路径规划策略 → 主服务热加载

```mermaid
sequenceDiagram
    participant V as platform-vue
    participant P as Platform
    participant L as SimpleLite
    participant E as DispatchLoop
    participant RV as rcsmonitor-vue

    V->>P: PUT /api/config/routing (payload, ifMatch=vPrev)
    P->>P: 校验 schema + 权限 (config.routing.write)
    P->>P: 写 platform.db (version+1, status=staged)
    P->>L: PUT /api/sl/config/routing (YARP)
    L->>L: ConfigSnapshot.AtomicSwap(vN)
    L->>E: OnConfigChanged(routing)
    E-->>L: ack
    L-->>P: 200 OK { version: vN }
    P->>P: status=active
    P-->>V: 200 OK + 当前版本
    P-->>RV: WS broadcast { type: "config.updated", section: "routing", version: vN }
```

### 10.5 rcsmonitor-vue 发「取消任务」运维命令

```mermaid
sequenceDiagram
    participant U as 运营人员
    participant RV as rcsmonitor-vue
    participant P as MiGu.Server (YARP)
    participant L as SimpleLite (Ops 网关)
    participant E as DispatchLoop
    participant DBp as platform.db
    participant DBl as simple_main.db

    U->>RV: 选中 Demand → 点击「取消」
    RV->>RV: 客户端权限校验 (ops.task.cancel ∈ allowedOps?)
    RV->>U: 二次确认
    U->>RV: 确认
    RV->>P: POST /api/sl/ops/task/cancel<br/>{demandId, idempotencyKey, reason}
    P->>P: JWT + scope=RCSMonitor + 路径前缀 /api/sl/ops/* 命中白名单
    P->>L: POST /api/ops/task/cancel (YARP + X-On-Behalf-Of + svcToken)
    L->>L: 服务端鉴权 (ops.task.cancel) + 白名单 + 限流 + 幂等
    L->>E: Pool.CancelDemand(id)
    E-->>L: result
    L->>DBl: 写 OpsAuditLog
    L-->>P: 200 OK { status, auditId }
    P->>DBp: 写 OpsLogs(source=RCSMonitor, auditId)
    P-->>RV: 200 OK
    RV-->>U: 提示成功
```

### 10.6 ROSE 主备切换序列

```mermaid
sequenceDiagram
    participant CLI as 客户端 (Vue/车端)
    participant VIP as 浮动 IP
    participant NA as NODE-A (Active)
    participant ROSE as ROSE HA Engine
    participant NB as NODE-B (Standby)

    CLI->>VIP: REST / WS 请求
    VIP->>NA: 路由到 Active
    Note over NA: 节点故障
    ROSE->>NA: 心跳超时 → 触发切换
    ROSE->>NA: 强制停止 SimpleLite / Platform
    ROSE->>NA: 卸载 R: 卷
    ROSE->>NB: 挂载 R: 卷
    ROSE->>NB: 启动 SimpleLite (WAL 重放 + 主库自检)
    ROSE->>NB: 启动 MiGu.Server
    ROSE->>VIP: 浮动 IP 漂移到 NODE-B
    CLI--xVIP: 短暂中断
    CLI->>VIP: 重连 (WS auto-reconnect)
    VIP->>NB: 路由到 NODE-B (新 Active)
    NB-->>CLI: 恢复服务
    Note over CLI,NB: RTO 目标 < 60s，RPO ≈ 0
```

---

## 11. 通信协议矩阵

| 通道 | 协议 | 编码 | 端点 | 用途 |
|------|------|------|------|------|
| MiGu.Server (YARP) ↔ SimpleLite | REST / WebSocket | JSON | `:7001` / `:7002` | 全功能 API 反代 + 事件订阅 |
| platform-vue ↔ MiGu.Server | REST / WebSocket | JSON | `:8080` / `:8081` （路径前缀 `/admin`） | UI 操作、事件推送 |
| rcsmonitor-vue ↔ MiGu.Server | REST / WebSocket | JSON | `:8080` / `:8081` （路径前缀 `/monitor`，`scope=RCSMonitor`） | UI 操作、事件推送（受限） |
| Vue Workspace3D ↔ SimpleLite WebTerminal | WSS（webVRender 协议） | webVRender 自有 | `:8223` | 3D 视口同步（嵌入 iframe） |
| 子进程心跳 | Named Pipe | JSON | `\\.\pipe\simple-bootstrap` | 守护 / 重启 |
| Vehicle ↔ SimpleLite | TCP / WS / OPC-UA | 业务私有 | `:8222` | 车端协议 |
| ROSE 心跳 | 专用网卡 + 串口 | ROSE 私有 | — | 节点健康监测 |
| ROSE 镜像复制 | 专用网卡 | ROSE 私有 | — | 块级实时数据同步 |

**WebAPI 约定：**

- 资源路径：`/api/{domain}/{resource}`，例：`/api/ops/task/cancel`、`/api/projection/map`、`/api/config/routing`；Platform 反代前缀 `/api/sl/*`
- 鉴权：`Authorization: Bearer <JWT>`；服务间互调附 `X-Svc-Token` + `X-On-Behalf-Of: <userId>` + `X-Scope: <scope>`
- 幂等：写操作支持 `Idempotency-Key` 请求头
- 版本化：配置类资源使用 `ETag` / `If-Match` 做乐观锁
- Swagger：Platform / SimpleLite 都暴露 `/swagger`（生产可关）
- **YARP Scope 白名单**：`scope=RCSMonitor` 时仅允许 `/api/sl/ops/*` 与 `/api/sl/projection/*` 命中；其他路径直接 403

---

## 12. 部署拓扑

```mermaid
flowchart TB
    subgraph Cluster["双机 ROSE HA 集群 (Web-Enabled)"]
        subgraph NA["NODE-A (Active)"]
            SL_A["SimpleLite.exe<br/>Kestrel :7001/7002<br/>WebTerminal :8223"]
            PL_A["MiGu.Server.exe<br/>:8080/8081<br/>(YARP + 双 Vue dist)"]
            R_A["ROSE 受保护盘 R:\<br/>两库 (WAL)"]
        end
        subgraph NB["NODE-B (Standby)"]
            SL_B["SimpleLite.exe (suspended)"]
            PL_B["MiGu.Server.exe (suspended)"]
            R_B["ROSE 镜像盘 R:\<br/>(实时同步)"]
        end
        NA <-- "ROSE 块级镜像 + 心跳" --> NB
        VIP(("浮动 IP / VIP"))
        VIP --> NA
    end

    subgraph Clients["客户端"]
        Op["管理员浏览器<br/>https://vip:8080/admin"]
        Run["运营浏览器<br/>https://vip:8080/monitor"]
        Veh["AGV 车端"]
    end

    subgraph Cold["冷备 / 归档"]
        NAS["NAS / 对象存储<br/>(夜间快照 + WAL 归档)"]
    end

    Op -- "HTTPS :8080" --> VIP
    Run -- "HTTPS :8080" --> VIP
    Veh -- "TCP :8222" --> VIP

    NA -. "夜间 sqlite_backup + WAL 归档" .-> NAS
```

**端口规划（单逻辑节点）：**

| 端口 | 服务 | 启用条件 |
|------|------|----------|
| 7001 | SimpleLite WebAPI | Web-Enabled |
| 7002 | SimpleLite WebSocket | Web-Enabled |
| 8080 | Platform WebAPI + platform-vue 静态（/admin）+ rcsmonitor-vue 静态（/monitor） | Web-Enabled |
| 8081 | Platform WebSocket | Web-Enabled |
| 8222 | SimpleLite 车端 / API（现有） | 所有模式 |
| 8223 | SimpleLite WebTerminal（webVRender，Vue 嵌入用） | Web-Enabled |

> Desktop-Only 模式下：7001 / 7002 / 8080 / 8081 / 8223 全部**不监听**。

---

## 13. 仓库与解决方案规划

```mermaid
flowchart LR
    subgraph repo["Simple-FR 仓库"]
        sln["Simple.sln"]

        subgraph kernel["内核 (现有)"]
            SC["SimpleCore"]
            SS["SimpleScheduler"]
            HC["HttpClientHelper"]
        end
        subgraph shared["共享 (新增)"]
            SHC["SimpleShared.Contracts"]
            SHA["SimpleShared.Auth"]
            SHF["SimpleShared.Config"]
            SHP["SimpleShared.Persistence"]
            SHO["SimpleShared.OpsCommand"]
            SHH["SimpleShared.WebApiHost"]
        end
        subgraph apps["两端后端"]
            SL["SimpleLite (CycleGUI + WebAPI)"]
            PSrv["MiGu.Server (WebAPI + YARP)"]
        end
        subgraph frontends["前端 (pnpm workspace)"]
            ShComp["packages/sl-controls<br/>(共享 Vue 组件库, 含 Workspace3D)"]
            PVue["platform-vue (Vue 3 + Vite)"]
            RVue["rcsmonitor-vue (Vue 3 + Vite)"]
        end
        subgraph plugins["插件"]
            PG["Plugins / Sample / 第三方"]
        end
        subgraph ops["运维脚本"]
            HA["tools/ha/<br/>(ROSE 资源脚本 + 切换演练)"]
        end
    end

    SL --> SC
    SL --> SS
    SL --> HC
    SL --> SHC
    SL --> SHA
    SL --> SHF
    SL --> SHP
    SL --> SHO
    SL --> SHH

    PSrv --> SC
    PSrv --> SHC
    PSrv --> SHA
    PSrv --> SHF
    PSrv --> SHP
    PSrv --> SHO
    PSrv --> SHH

    PG -. 反射加载 .-> SL
    ShComp --> PVue
    ShComp --> RVue
    PVue -- vite build --> PSrv
    RVue -- vite build --> PSrv
```

### 13.1 pnpm workspace 配置示例

`frontends/pnpm-workspace.yaml`：

```yaml
packages:
  - packages/*
  - apps/*
```

`frontends/` 目录结构：

```text
frontends/
├── pnpm-workspace.yaml
├── package.json
├── packages/
│   └── sl-controls/         # 共享组件库（Workspace3D / MapEditor / CarPanel / MissionEditor / CadToolbar / OpsActionPanel / FieldsLayers ...）
│       ├── package.json
│       ├── src/
│       │   ├── Workspace3D.vue   # 嵌入 webVRender iframe
│       │   ├── MapEditor.vue
│       │   ├── ...
│       │   └── index.ts
│       └── tsconfig.json
└── apps/
    ├── platform-vue/        # 管理员前端
    │   ├── package.json     # depends on "@simple/sl-controls"
    │   └── src/
    └── rcsmonitor-vue/      # 运营前端
        ├── package.json     # depends on "@simple/sl-controls"
        └── src/
```

`packages/sl-controls/package.json`（节选）：

```json
{
  "name": "@simple/sl-controls",
  "version": "0.1.0",
  "main": "src/index.ts",
  "peerDependencies": {
    "vue": "^3.4.0"
  }
}
```

`apps/platform-vue/package.json`（节选）：

```json
{
  "dependencies": {
    "@simple/sl-controls": "workspace:*",
    "vue": "^3.4.0",
    "pinia": "^2.1.0",
    "vue-router": "^4.2.0",
    "element-plus": "^2.5.0",
    "echarts": "^5.5.0"
  }
}
```

构建 + 部署：

```bash
cd frontends
pnpm install
pnpm --filter platform-vue build      # 产出 apps/platform-vue/dist
pnpm --filter rcsmonitor-vue build    # 产出 apps/rcsmonitor-vue/dist
# MiGu.Server 的发布脚本将这两个 dist 复制到 MiGu.Server/wwwroot/{admin,monitor}
```

---

## 14. 落地路线图

| 里程碑 | 周期估计 | 交付内容 |
|--------|----------|----------|
| **M0 - 内核下沉** | 1 周 | 新建 SimpleShared.* 6 个工程；Configuration → IConfigSnapshotProvider；EF Core + SQLite + 迁移 |
| **M1 - 启动登录 + 运行模式** | 1 周 | `BootLoginPanel`；`RunMode` 枚举；CycleGUI 状态窗；`simple.json.runMode` 持久化；Web-Enabled 业务面板硬隐藏 |
| **M2 - WebAPI 协议层** | 1.5 周 | SimpleLite 集成 Kestrel；定义 `/api/projection/*`、`/api/ops/*`、`/api/config/*`、`/api/map/*` 等；WS Hub；JWT |
| **M3 - 共享前端组件库** | 1.5 周 | `frontends/packages/sl-controls`：Workspace3D（嵌入 webVRender）+ 地图列表 + 任务表 + CAD 工具栏 + OpsActionPanel 等 |
| **M4 - Platform 后端 + YARP** | 2 周 | MiGu.Server（WebAPI + Swagger + YARP `/api/sl/*` + Scope 中间件 + 静态托管双 Vue dist）+ 配置中心 11 个 schema + 用户/角色/控件权限 |
| **M5 - platform-vue (管理员)** | 2.5 周 | 全功能套壳：登录、地图设计、车辆/任务、CAD、字段/图层、配置中心、库位、自定义控件、回放、设备管理、车队生命周期、场景模板 |
| **M6 - rcsmonitor-vue (运营)** | 1.5 周 | 按权限渲染；嵌入 webVRender（read-only）；运维白名单动作面板；标注 |
| **M7 - Bootstrapper** | 1 周 | SystemMission 启动 Platform + 心跳 + Watchdog |
| **M8 - 高可用方案落地** | 2 周 | 默认路径 SQLite + ROSE（数据盘 / 启停脚本 / VIP / 切换演练，RTO < 60s 验收）；另出 MySQL InnoDB Cluster / PostgreSQL Patroni / SQL Server Always On AG 三份部署指南与 CI 流水线 |
| **M9 - 自定义控件 + 控件级权限** | 2 周 | 控件 schema → platform-vue + rcsmonitor-vue 双渲染器；按 `WidgetGrant` 三档可见性裁剪 |

---

## 15. 已确认决策

| # | 议题 | 决策 |
|---|------|------|
| 1 | 运行模式持久化 | **写入 `simple.json.runMode` / `rememberRunMode`**（不使用 %APPDATA%） |
| 2 | Web-Enabled 下是否允许同时本地操作 | **不允许**；CycleGUI 仅状态窗；不提供"临时启用本地 UI"开关 |
| 3 | 3D 引擎 | **复用 SimpleLite WebTerminal 的 webVRender**，Vue 通过 iframe / Web Component 嵌入 |
| 4 | 反向代理 | **YARP**（MiGu.Server 用 YARP 反代 `/api/sl/*`） |
| 5 | RCSMonitor 是否需要独立后端 | **否**，完全依赖 MiGu.Server；通过 `scope=RCSMonitor` + 角色 + WidgetGrant 限权 |
| 6 | 共享前端组件库 | **pnpm workspace + `frontends/packages/sl-controls`** |
| 7 | 运营白名单 | 采纳 §5.1 列表（10 条，后续可扩） |
| 8 | ROSE 复制粒度 | 块级镜像盘（RPO≈0）首选；视现场版本兜底文件级 |
| 9 | 车端连接策略 | 走 VIP，统一切换；车端实现 WS 自动重连 |
| 10 | **Platform / RCSMonitor 启动归属（v1.4）** | **由 SimpleLite 内置 `SystemMission.StartPlatformMission` 拉起并守护**；不允许独立安装 MiGu.Server.exe 为 Windows Service；MiGu.Server 启动时校验父进程必须是 SimpleLite |
| 11 | **持久层多 Provider（v1.5）** | EF Core 抽象，**默认 SQLite + ROSE HA**；可选 **MySQL InnoDB Cluster / PostgreSQL Patroni / SQL Server Always On AG**；每 Provider 一套 EF Migrations，CI 全矩阵跑通；运行期由 `simple.json.database.provider` 决定 |
| 12 | **跨 Provider 切换策略** | 不支持热切；切换走停服窗口 + `tools/db/migrate.ps1`；旧文件作为回退包保留 |

---

## 16. 现有代码影响面

| 现有文件 | 改动方向 |
|----------|----------|
| `SimpleLite/Program.cs` | 在 `Enssentials.Load` 之后插入 `BootLoginPanel.RunModal()`；根据返回的 `RunMode` 决定后续路径 |
| `SimpleLite/Configuration.cs` | 拆为 `LocalBootConfig`（启动期，含 `runMode`、`rememberRunMode`、监听地址、各端口）+ `IConfigSnapshotProvider`（运行期）；数据库路径走 `%SIMPLE_DATA_ROOT%` |
| `SimpleLite/Startup.cs` | 按 `RunMode` 分支：Desktop-Only 走原有 CycleGUI；Web-Enabled 启动 Kestrel + WebAPI + WebTerminal + Spawn Platform + 切换 CycleGUI 到状态窗 |
| `SimpleLite/UI/SimpleUI.cs` | 增加 `RunMode.WebEnabled` 时**所有业务面板硬性不创建**；新增"服务状态窗"面板（唯一允许） |
| `SimpleLite/UI/BootLoginPanel.cs`（新增） | 启动登录窗实现 + 模式持久化 |
| `SimpleLite/UI/ServiceStatusPanel.cs`（新增） | Web-Enabled 状态窗实现 |
| `SimpleLite/RCS/Mission.cs` | 抽出 `SystemMission` 抽象基类（与业务 Mission 同一基类但走独立 Registry，**不进入 DispatchLoop**） |
| `SimpleLite/RCS/SystemMissions/StartPlatformMission.cs`（新增） | 拉起 `MiGu.Server.exe`、绑定命名管道、上报心跳与状态到 ServiceStatusPanel |
| `SimpleLite/Bootstrap/ProcessHost.cs`（新增） | 封装 `System.Diagnostics.Process` + 日志重定向 + 优雅停止 |
| `SimpleLite/Bootstrap/HeartbeatChannel.cs`（新增） | 命名管道服务端 + JSON 心跳协议 |
| `SimpleLite/Bootstrap/SystemMissionRegistry.cs`（新增） | 注册/批量 Spawn/Stop SystemMission |
| `SimpleLite/Bootstrap/ProcessWatchdog.cs`（新增） | 指数退避重启 + 多次失败后熔断并通知状态窗 |
| `SimpleLite/Bootstrap/RunMode.cs`（新增） | `DesktopOnly` / `WebEnabled` 枚举 + 启动期校验 |
| `SimpleLite/Rendering/SimpleSceneRenderer.cs` | 按 webVRender 的 `?scope=` / `?ro=` 参数禁用编辑工具 |
| `SimpleScheduler/WebApi.cs` | 调用方从 Nancy 切到 ASP.NET Core Controller；保持 `SchedulerRuntime` 外观稳定 |
| `SimpleLite/SimpleProject.cs` | 持久化双写：JSON（兼容）+ SQLite（新主存，受 ROSE 保护盘） |
| `Plugins/Sample` | 示例插件读取 `IConfigSnapshotProvider`；不再读 `Configuration.conf` |
| 新增 `tools/ha/*` | ROSE 资源启停脚本、健康检查脚本、切换演练脚本 |
| 新增 `tools/db/*` | 跨 Provider 迁移脚本（`migrate.ps1` / `dump.ps1` / `restore.ps1`）；按目标 DB 校验 schema 与索引 |
| 新增 `SimpleShared.Persistence/Providers/*` | 四个 Provider 适配（`SqliteProviderAdapter` / `MySqlProviderAdapter` / `NpgsqlProviderAdapter` / `SqlServerProviderAdapter`）+ `IDbProviderSpecifics` |
| 新增 `SimpleShared.Persistence/Migrations/{Sqlite,MySql,Npgsql,SqlServer}/*` | 四套 EF Core 迁移文件，CI 矩阵跑全 |
| 新增 `frontends/pnpm-workspace.yaml` | pnpm workspace 根 |
| 新增 `frontends/packages/sl-controls/` | 共享 Vue 组件库（含 Workspace3D 嵌 webVRender） |
| 新增 `frontends/apps/platform-vue/` | Vue 3 + Vite 工程，管理员全功能套壳 |
| 新增 `frontends/apps/rcsmonitor-vue/` | Vue 3 + Vite 工程，运营按权限渲染 |
| 新增 `MiGu.Server` 工程 | ASP.NET Core 8 WebAPI + YARP + 静态托管双 Vue dist |

---

## 17. 视觉规范（v1.6 新增，v1.6.1 对齐 FRLD）

### 17.1 品牌

| 项 | 取值 | 出现位置 |
|----|------|----------|
| 产品名 | **迷毂** | 登录窗标题 / `<title>` / 浏览器 favicon / 顶栏侧栏 logo / 文档抬头 |
| 全称 | **迷毂 · 智能调度平台** | 登录窗 H1、侧边栏中文标题 |
| 英文 | **Mi Gu · Intelligent Dispatch Platform** | 登录窗副标题、侧边栏英文副标 |
| 母公司 | **法睿兰达 FAIRYLAND**（FRLD） | 登录卡 / 侧边栏 顶部 logo |
| 工程标识（保持不动） | `MiGu.Server` / `simple-platform-vue` | csproj 名 / pnpm 包名 / 仓库目录；保持稳定避免破坏构建脚本 |
| Logo 资源 | `public/FRLD-logo-white.png` (11.5 KB) 展开态 + `public/FRLD-logo-white-no_title.png` (3.5 KB) 折叠态 | 侧边栏 / 登录卡；来源 `E:\ddms\frontend\public`（与 FAME 共用） |
| Favicon | `public/favicon.svg`（紫色渐变方块 + 白色「迷」字） | 浏览器标签页 |
| 登录背景 | `public/login-bg.jpg`（1.8 MB，原始素材 `C:\Tool\wallpapper\wall_Beach.jpg`） | 海滩 + 紫色叠加层 |

### 17.2 主色卡（v1.7 默认 · 工业紫色）

**默认主题 `industrial-purple`（工业紫）** — 登录后内容区与 AppShell 的基准色：

```
主色 PRIMARY        #5a1890   rgb(90, 24, 144)
悬停 HOVER          #7b1fa2   rgb(123, 31, 162)
按下 ACTIVE         #38006b
强调 ACCENT         #8e6abf   rgb(142, 106, 191)

应用渐变起/中/止   #0c021c → #16082e → #04000e（内容卡片 92%+ 不透明，避免发灰）
侧栏渐变           rgba(--mg-bg-aside-rgb) → rgba(--mg-bg-app-deep-rgb)
```

> **历史**：v1.6.2 固定 `#641393`；v1.6.1 曾对齐 ddms 的 `#7c3aed`。v1.7 起以 `themes.ts` 为唯一色板源，`theme.css` 仅提供默认值与玻璃令牌。
>
> 实现位置：
> - `frontends/apps/simple-platform-vue/src/styles/themes.ts` — 6 套预设 + `applyThemeVars()`
> - `frontends/apps/simple-platform-vue/src/styles/theme.css` — `--mg-*` + Element Plus 覆盖
> - `frontends/apps/simple-platform-vue/src/stores/ui.ts` — `themeId` 持久化

### 17.3 状态色

为保持紫色品牌统一，状态色降饱和并往紫色侧偏移：

| 状态 | 取值 | RGB |
|------|------|-----|
| 成功 | `#6f8f4c` | 111, 143, 76 |
| 警告 | `#c98a1d` | 201, 138, 29 |
| 危险 | `#b3324f` | 179, 50, 79 |
| 信息 | `#7a6b87` | 122, 107, 135 |

### 17.4 登录窗视觉构成（§3.2 的物化形态，v1.6.1 对齐 ddms）

1. **背景层 (`z-index:0`)**：`url('/login-bg.jpg') center/cover`，filter `saturate(0.45) brightness(0.42)`，transform `scale(1.05)`。
2. **紫色叠加层 (`z-index:1`)**：径向渐变（左上 `rgba(168,85,247,0.55)` + 右下 `rgba(26,16,64,0.78)`）+ 主对角线深紫线性渐变。
3. **辉光球 (`z-index:1`)**：两个 blur(85px) 圆斑（左上 440px violet-300、右下 560px purple-500），各自 drift 18s 错相位呼吸。
4. **登录卡 (`z-index:2`)**：460px 宽，圆角 16px，背景 `linear-gradient(135deg, #2d1b69 0%, #7c3aed 100%)`，`box-shadow: 0 30px 80px rgba(10,10,40,0.55)` + 内边高光。
5. **品牌区**：52px FRLD logo（drop-shadow violet glow）+ H1 `迷 毂 · 智能调度平台`（letter-spacing 3px）+ 副标 `Mi Gu · Intelligent Dispatch Platform`（首字母 bolded）+ hint `请登录您的账号 · Web-Enabled`。
6. **表单**：透明 el-input（白字 + 半透明白边 + focus 紫色辉光）+ scope 双卡（选中态白底紫字）+ checkbox（白勾紫底）+ 高级折叠（端口配置 2x2 grid）+ 白底紫字 46px 大圆角主按钮（hover 上浮 2px）。

### 17.5 AppShell 视觉构成（v1.6.1 对齐 ddms）

1. **侧边栏**：自顶向下渐变 `#2d1b69 → #1a1040`，宽度 232px（折叠 64px），右侧细边 + `box-shadow: 2px 0 16px rgba(26,16,64,0.25)`。
2. **侧边栏顶端 Logo 块**：22/14 内边距，38px FRLD logo（drop-shadow `rgba(168,85,247,0.4)`），下方中文标题 `迷 毂 · 智能调度平台`（letter-spacing 2.5px）+ 英文副标 `Mi Gu · Intelligent Dispatch Platform`（首字母 bolded）。
3. **折叠态**：仅显示 28px FRLD 小 logo + 「迷毂」缩写。
4. **菜单态**：item margin 2/8 + 44px 高 + 圆角 8px；hover `rgba(168,85,247,0.18)`；active `linear-gradient(90deg, rgba(168,85,247,0.38), rgba(124,58,237,0.22))` + `inset 3px 0 0 #a855f7`。
5. **顶栏**：白底 + `box-shadow: 0 1px 6px rgba(45,27,105,0.06)`；面包屑 `#2d1b69`、分隔符 `#c4b5fd`。
6. **用户头像**：`linear-gradient(135deg, #a855f7, #7c3aed)` 圆形。
7. **页脚**：`color: var(--mg-primary-700)`、`border-top: 1px solid #f0ebf8`。

### 17.6 复用清单

要在新页面/组件中沿用品牌主色，优先使用 CSS 变量：

| 变量 | 用途 |
|------|------|
| `--mg-primary` | 任意主色字段（按钮、链接、强调） |
| `--mg-primary-{50..900}` | 主色阶梯，用于底色/边框/浅文字 |
| `--mg-bg-app` / `--mg-bg-aside` / `--mg-bg-aside-2` | 全局/侧边栏底色 |
| `--mg-text-light` / `--mg-text-muted` | 暗背景文本 |
| `--mg-divider` | 暗背景分割线 |
| Element Plus 自带 `var(--el-color-primary*)` | 已自动跟随主色 |

新写视图时请避免硬编码 `#641393` / `#7c3aed`（统一走 `var(--mg-primary)`、`rgba(var(--mg-*-rgb), α)`，以便主题切换生效）。

### 17.7 多主题色板切换（v1.7 新增）

| 文件 | 职责 |
|------|------|
| `src/styles/themes.ts` | `ThemePreset[]`：id / name / description / preview / `vars`（`--mg-*` 键值对） |
| `src/styles/theme.css` | 静态默认 + 玻璃令牌 + `.mg-content` 内 Element Plus 暗色适配 |
| `src/stores/ui.ts` | `themeId`、`setThemeId()`、`applyCurrentTheme()`、`localStorage` 键 `simple.ui.state` |
| `src/components/ThemeSwitcher.vue` | 顶栏下拉：色块预览 + 名称/描述 + 当前勾选 |
| `src/layouts/AppShell.vue` | 头部接入 `ThemeSwitcher`；壳层样式使用 `var(--mg-*)` |
| `src/main.ts` | `createPinia()` 后立即 `useUiStore(pinia).applyCurrentTheme()` |

**6 套预设 ID：**

| id | 名称 | 主色 preview |
|----|------|----------------|
| `industrial-purple` | 工业紫色（**默认**） | `#5a1890` |
| `deep-azure` | 深邃蓝 | `#1565c0` |
| `emerald-forge` | 翡翠绿 | `#00796b` |
| `crimson-iron` | 熔铁赤 | `#b71c1c` |
| `graphite-steel` | 石墨钢 | `#455a64` |
| `amber-forge` | 琥珀金 | `#e65100` |

**切换流程：** 用户选主题 → `setThemeId` → `applyThemeVars` 写 `:root` + `data-theme` 属性 → `persist()`。刷新页面后 `main.ts` 恢复。

**构建验证：** `pnpm --filter simple-platform-vue exec vue-tsc --noEmit` + `pnpm --filter simple-platform-vue build`（2026-05-20 已通过）。

---

## 18. 实现进度与待办（对照代码库）

> 工作目录：`E:\Work\Core\Simple-FR\Simple`。下列状态以仓库内**实际文件**为准，与 §14 里程碑对照；完成项在后续 PR/会话中应同步更新本表。

### 18.1 前端 `simple-platform-vue`（合并 admin + monitor）

| # | 项 | 文档依据 | 状态 | 代码位置 / 备注 |
|---|-----|----------|------|-----------------|
| F1 | pnpm workspace + 单 SPA | §13、frontends/README | ✅ 完成 | `frontends/apps/simple-platform-vue`；路由 `/admin/*` `/monitor/*` |
| F2 | 登录窗 §3.2 | §3.2、§17.4 | ✅ 完成 | `LoginView.vue`：双栏 hero、海滩背景、Mock 鉴权 |
| F3 | AppShell 玻璃风 | §17.5、v1.6.2 | ✅ 完成 | `AppShell.vue`：侧栏 FRLD logo、菜单、fade-up |
| F4 | Workspace3D / webVRender | §1、§11 | ✅ 完成 | `Workspace3D.vue` → `:8223` iframe |
| F5 | 配置中心 14 页骨架 | §9 | ✅ 完成 | `views/admin/config/*` + `ConfigPageBase` |
| F6 | 运营 monitor 视图 | §5、M6 | ✅ 骨架 | `views/monitor/*`（与 admin 同工程） |
| F7 | **多主题色板** | §17.7（v1.7） | ✅ 完成 | `themes.ts`、`ThemeSwitcher.vue`、`ui.ts`、`main.ts` |
| F8 | AppShell 壳层随主题变色 | §17.7 | ✅ 完成 | `AppShell.vue` 已改 `var(--mg-*)` |
| F9 | 登录页随主题变色 | §17.7 | ✅ 完成 | `BlankLayout` / `LoginView` 光球、叠加层、hero、按钮已改 `var(--mg-*)`；登录页内切换器仍 ☐（登录后顶栏可切） |
| F10 | `DashboardView` 图表色板 | §17.6 | ☐ 待办 | `MG_PALETTE` 仍为固定紫色数组，应读 `activeTheme` |
| F11 | 独立 `platform-vue` / `rcsmonitor-vue` | §13 | ☐ 未拆 | 当前有意合并；拆分时更新构建脚本 |
| F12 | `packages/sl-controls` | §13、M3 | ☐ 未建 | 组件仍在 app 内 `components/` |
| F13 | dist → `MiGu.Server/wwwroot` | §13 构建说明 | 🔄 需手动 | build 后复制 `dist/*`；`Program.cs` 已 `MapFallbackToFile` |

### 18.2 后端 `MiGu.Server`（骨架）

| # | 项 | 状态 | 备注 |
|---|-----|------|------|
| B1 | Kestrel + Swagger + CORS | ✅ | `Program.cs` |
| B2 | Auth / Health / Config / Ops / Projection 控制器 | ✅ 骨架 | Mock/内存存储 |
| B3 | YARP `/api/sl/*` → :8222 | ✅ 配置 | 依赖 SimpleLite 实际监听 |
| B4 | 静态托管 + SPA fallback | ✅ | 单一 `wwwroot/index.html` |
| B5 | JWT 真签发 + 库持久化 | ☐ | 仍为 Mock |
| B6 | 父进程 SimpleLite 校验 | ☐ | §4、§15 #10 |

### 18.3 SimpleLite / 共享内核（ARCHITECTURE 主体）

| # | 项 | 状态 | 备注 |
|---|-----|------|------|
| S1 | `SimpleShared.*` 六工程 | ☐ 未建 | §6、M0 |
| S2 | `BootLoginPanel` + `RunMode` | ☐ | M1 |
| S3 | `SystemMission.StartPlatformMission` | ☐ | M7 |
| S4 | WebAPI Kestrel + WS | ☐ | M2 |
| S5 | 多 DB Provider + HA | ☐ | M0/M8 |

### 18.4 主题功能子任务（v1.7 专项）

| # | 子任务 | 状态 |
|---|--------|------|
| T1 | `themes.ts` 六套预设，工业紫默认 | ✅ |
| T2 | `theme.css` 全站 `--mg-*` + `.mg-content` EP 覆盖 | ✅ |
| T3 | `ui.ts`：`themeId` + `applyCurrentTheme` + localStorage | ✅ |
| T4 | `ThemeSwitcher.vue` 下拉组件 | ✅ |
| T5 | `AppShell` 顶栏接入 | ✅ |
| T6 | `main.ts` 启动恢复主题 | ✅ |
| T7 | `vue-tsc` + `vite build` | ✅ 2026-05-20 |
| T8 | 登录页变量化 + 可选登录页 ThemeSwitcher | 🔄 T8a 变量化 ✅；T8b 登录页 ThemeSwitcher ☐ |
| T9 | `ARCHITECTURE.md` / `frontends/README.md` 同步 | ✅ 本节 |

---

## 关联文档

- [SIMPLELITE_DEVELOPMENT_PLAN.md](./SIMPLELITE_DEVELOPMENT_PLAN.md) — SimpleLite 功能对齐执行计划
- [SIMPLELITE_COMPOSER_PARITY_PLAN.md](./SIMPLELITE_COMPOSER_PARITY_PLAN.md) — 与 SimpleComposer 差距分析
