245 lines
12 KiB
Markdown
245 lines
12 KiB
Markdown
# MiGu.Server
|
||
|
||
> 「**迷毂 · 智能调度平台**」的后端骨架(ASP.NET Core 8 + YARP)。
|
||
> 对应 [ARCHITECTURE.md](ARCHITECTURE.md) v1.6 §1.1 中提到的「Platform 管理端」后端可执行文件。
|
||
>
|
||
> **会话 N+1(启动反转):现在 `MiGu.Server.exe` 是主入口**。
|
||
> 用户先启动 MiGu.Server,浏览器登录页选择「启动模式」(本地+Web / 仅Web),
|
||
> 后端 `AuthController.Login` 调用 `SimpleLiteLauncher.MaybeStart(launchMode)` 按所选模式拉起 `SimpleLite.exe`,
|
||
> 通过 `--display-mode=web|web+local` 透传给 SimpleLite 的 `Configuration.displayMode`。
|
||
>
|
||
> 工程名 `MiGu.Server` / 程序集 `MiGu.Server.dll` 保持稳定,仅用户可见前端文案改为「迷毂」。
|
||
|
||
## 克隆后首次部署速查(必读)
|
||
|
||
本仓库为 **Migu2.0**,已包含预构建的 `wwwroot/` 前端,克隆后可直接编译运行 MiGu.Server。
|
||
|
||
```pwsh
|
||
# 1) 编译 MiGu.Server
|
||
cd MiGu.Server
|
||
dotnet build MiGu.Server.csproj -c Debug
|
||
|
||
# 2) 启动(登录后按所选模式拉起 SimpleLite)
|
||
dotnet run
|
||
# 或:.\bin\Debug\net8.0\MiGu.Server.exe
|
||
```
|
||
|
||
**更新前端**:在 Simple 仓库执行 `build-platform-frontend.bat`,将 `frontends/apps/simple-platform-vue/dist/` 同步到本目录 `wwwroot/`。
|
||
|
||
## 配置 SimpleLite 路径(必读)
|
||
|
||
> **配置文件位置(无 Web 界面):**
|
||
> **`MiGu.Server/appsettings.json`** → 搜索 **`"SimpleLite"`** 节点。
|
||
> 登录页选「本地 + Web / 仅 Web」后,后端在此配置的路径拉起 `SimpleLite.exe`。
|
||
> 启动后可在浏览器打开 **`http://localhost:8080/api/health/simplelite`** 查看路径是否解析成功。
|
||
|
||
登录成功后,MiGu.Server 会按所选启动模式拉起 **SimpleLite.exe**。默认已在 `appsettings.json` 写好与 Simple 仓库并列的相对路径;开发机可用 `appsettings.Development.json` 覆盖为绝对路径。
|
||
|
||
### 本机开发(与 Simple 仓库并列)
|
||
|
||
仓库默认已在 `appsettings.Development.json` 中写好:
|
||
|
||
```json
|
||
"SimpleLite": {
|
||
"Enabled": true,
|
||
"ExecutablePath": "E:\\Work\\Core\\Simple-FR\\Simple\\SimpleLite\\bin\\Debug\\SimpleLite.exe",
|
||
"WorkingDirectory": "E:\\Work\\Core\\Simple-FR\\Simple\\SimpleLite\\bin\\Debug",
|
||
"ProjectionPort": 8222,
|
||
"ReadinessTimeoutMs": 8000,
|
||
"FollowParent": false
|
||
}
|
||
```
|
||
|
||
请先编译 SimpleLite(在 Simple 仓库):
|
||
|
||
```pwsh
|
||
cd ..\Simple
|
||
dotnet build SimpleLite\SimpleLite.csproj -c Debug
|
||
```
|
||
|
||
若你的 Simple 不在上述绝对路径,可改为**相对路径**(相对 `MiGu.Server` 工作目录):
|
||
|
||
```json
|
||
"ExecutablePath": "..\\..\\Simple\\SimpleLite\\bin\\Debug\\SimpleLite.exe",
|
||
"WorkingDirectory": "..\\..\\Simple\\SimpleLite\\bin\\Debug"
|
||
```
|
||
|
||
### 配置项说明
|
||
|
||
| 键 | 含义 |
|
||
|----|------|
|
||
| `Enabled` | `false` 时永不拉起 SimpleLite(只调试平台 UI) |
|
||
| `ExecutablePath` | `SimpleLite.exe` 绝对或相对路径;留空则自动探测(见 `Launcher/SimpleLiteOptions.cs`) |
|
||
| `WorkingDirectory` | 子进程工作目录;留空则用 exe 所在目录(读写 `simple.json` / `imgui.ini`) |
|
||
| `ProjectionPort` | 就绪检测端口,默认 `8222` |
|
||
| `ReadinessTimeoutMs` | 登录后等待 SimpleLite WebAPI 就绪的最长时间(毫秒) |
|
||
| `FollowParent` | `true` 时 MiGu.Server 退出会结束 SimpleLite;默认 `false`(两进程独立) |
|
||
|
||
### 环境变量覆盖
|
||
|
||
```pwsh
|
||
$env:SimpleLite__ExecutablePath = "D:\apps\SimpleLite.exe"
|
||
$env:SimpleLite__WorkingDirectory = "D:\apps"
|
||
$env:SimpleLite__Enabled = "true"
|
||
```
|
||
|
||
### 生产 / 合并发布
|
||
|
||
将 `SimpleLite.exe` 与依赖 DLL 放到 `MiGu.Server` 同目录,并清空 `ExecutablePath`(走自动探测 `./SimpleLite.exe`),或在 `appsettings.Production.json` 写死部署路径。
|
||
|
||
浏览器访问 `http://localhost:8080/login`:
|
||
1. 用户名 / 密码(`appsettings.json:Auth.Users` 默认 admin/admin、ops/ops);
|
||
2. 选 scope(管理员 / 运营);
|
||
3. 选 **SimpleLite 启动模式**:
|
||
- **本地 + Web** → 透传 `--display-mode=web+local`,桌面 ImGui 窗口 + 浏览器同时启动;
|
||
- **仅 Web** → 透传 `--display-mode=web`,只起 WebTerminal,不弹本地窗口;
|
||
4. 点登录。`AuthController.Login` 调用 `SimpleLiteLauncher.MaybeStart(...)` 阻塞等 Projection (`:8222`) 就绪后返回 LoginResponse。
|
||
|
||
> 如果只想跑 MiGu.Server 单进程调试(不拉 SimpleLite),把 `appsettings.json:SimpleLite.Enabled` 改为 `false` 即可。
|
||
|
||
## 安全须知(生产部署必读)
|
||
|
||
> **重要:以下默认值仅供本地开发,切勿原样用于生产环境。**
|
||
>
|
||
> - `appsettings.json:Auth.Users` 内置 `admin/admin`、`ops/ops` 为弱口令演示账号;
|
||
> - `appsettings.json:Jwt.Secret`、`Internal.Token` 为占位符 `REPLACE_ME`。
|
||
>
|
||
> 生产部署务必通过**环境变量**或 `appsettings.Production.json` / 密钥管理覆盖
|
||
> (ASP.NET Core 配置优先级:环境变量 > `appsettings.{Environment}.json` > `appsettings.json`)。
|
||
> 环境变量示例(`__` 双下划线表示配置层级):
|
||
>
|
||
> ```pwsh
|
||
> $env:Auth__Users__admin__Password = "<强密码>"
|
||
> $env:Jwt__Secret = "<不少于 32 字节的随机串>"
|
||
> $env:Internal__Token = "<随机串>"
|
||
> ```
|
||
>
|
||
> 详见代码审核 ISSUE-03(`Doc/CODE_REVIEW_ISSUES_2026-05-29.md`)。
|
||
>
|
||
> **SimpleLite 8222 内部 API(RV-04)**:默认 `simple.json:platform.allowLoopbackBypass=true`,本机回环请求免 token;**多租户 / 共享主机的生产环境建议设为 `false`**,强制所有请求携带 `X-Platform-Internal-Token`(配合 `platform.internalToken` 或 `MiGu.Server/data/.internal-token`)。详见复审 `Doc/CODE_REVIEW_WEEK_2026-05-29.md` RV-04。
|
||
|
||
## 能力清单(本轮)
|
||
|
||
- Kestrel 监听 `:8080`(HTTP);
|
||
- 静态托管:启动时自动探测 WebRoot ——
|
||
- 开发模式:仓库内 `frontends/apps/simple-platform-vue/dist/` 存在则直接挂为 WebRoot(`pnpm build` 后立即生效,无需 robocopy 到 wwwroot);
|
||
- 兜底/部署模式:找不到 dist 时回退到 `wwwroot/`(由 `build-platform-frontend.bat` 的 robocopy /MIR 填充);
|
||
- SPA fallback 让 `/admin/*` `/monitor/*` `/login` `/status` 等所有非 API 路径都回退到 `index.html`,由 vue-router 接管;
|
||
- YARP 反向代理:
|
||
- `/api/sl/{**catch-all}` → `http://127.0.0.1:8222/`(SimpleLite WebAPI;当前 SimpleLite 未启 WebAPI 时返回 502);
|
||
- `/vr/{**catch-all}` → `http://127.0.0.1:8223/`(webVRender;可用于同源 iframe 解决 X-Frame-Options 限制);
|
||
- 14 维度配置中心占位(对齐 §9):内存 + `data/config-{section}.json` 持久化;
|
||
- Mock 鉴权:`/api/auth/login` 返回 Mock JWT + `EffectivePermissions`;LoginRequest 新增 `launchMode: "WebOnly" | "DesktopAndWeb"` 字段,登录成功后 `SimpleLiteLauncher` 据此拉起子进程;
|
||
- SimpleLite 子进程编排:`Launcher/SimpleLiteLauncher.cs` 幂等 / Stdout 转发 / Windows JobObject 父子绑定 / 端口就绪等待,配置见 `appsettings.json:SimpleLite`;
|
||
- 运维白名单网关占位:`/api/sl/ops/execute`、`/api/sl/ops/audits`;
|
||
- 投影 API 占位:`/api/projection/{sites,tracks,cars,missions}`;
|
||
- 健康检查:`/api/health`;
|
||
- Swagger:开发环境下 `/swagger`。
|
||
|
||
> 不在本轮范围:真实 SimpleLite WebAPI、SystemMission 拉起、真实 JWT/RBAC、SQLite/EF Core 持久层。
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
MiGu.Server/
|
||
├── MiGu.Server.csproj
|
||
├── Program.cs # Kestrel + YARP + CORS + StaticFiles + SPA fallback
|
||
├── appsettings.json # YARP 路由 + CORS 白名单
|
||
├── appsettings.Development.json
|
||
├── Properties/launchSettings.json
|
||
├── Controllers/
|
||
│ ├── AuthController.cs # /api/auth/login | /api/auth/logout
|
||
│ ├── ConfigController.cs # GET/PUT /api/config[/{section}]
|
||
│ ├── ProjectionController.cs # /api/projection/{sites,tracks,cars,missions}
|
||
│ ├── OpsController.cs # /api/sl/ops/{execute,audits}
|
||
│ └── HealthController.cs # /api/health
|
||
├── Configs/ # 与 ARCHITECTURE.md §9 一一对齐的强类型 record
|
||
│ ├── SystemConfig.cs
|
||
│ ├── ExternalIntegrations.cs
|
||
│ ├── RoutingPolicy.cs
|
||
│ ├── VehicleMaintenancePolicy.cs
|
||
│ ├── ChargePolicy.cs
|
||
│ ├── TaskAllocationPolicy.cs
|
||
│ ├── TrafficRule.cs
|
||
│ ├── DeviceManagementConfig.cs
|
||
│ ├── FleetLifecycleConfig.cs
|
||
│ ├── ScenarioTemplateConfig.cs
|
||
│ ├── LocationManagement.cs
|
||
│ ├── OpsConfig.cs
|
||
│ ├── CustomWidget.cs
|
||
│ ├── EffectivePermissions.cs
|
||
│ └── ConfigStore.cs # 内存 + JSON 文件持久化(占位)
|
||
├── data/ # 运行时生成的 config-{section}.json
|
||
└── wwwroot/ # 部署兜底(dev 模式优先用 frontends/.../dist;assets/ 与 index.html 已 ignore)
|
||
```
|
||
|
||
## 独立启动(仅当你不通过 SimpleLite 自启时)
|
||
|
||
```pwsh
|
||
# 1) 还原 + 编译 + 运行
|
||
cd MiGu.Server
|
||
dotnet run
|
||
|
||
# 等价的 build + run 一键脚本:
|
||
.\build-and-run.bat # Debug
|
||
.\build-and-run.bat release # Release
|
||
|
||
# 2) 验证
|
||
# 打开 http://localhost:8080/ 欢迎页 / 平台前端
|
||
# 打开 http://localhost:8080/swagger API 文档
|
||
# 打开 http://localhost:8080/api/health 健康检查
|
||
# 打开 http://localhost:8080/api/config/system 系统级配置
|
||
```
|
||
|
||
或在 IDE 中以 `MiGu.Server` 作为启动项目。
|
||
|
||
> 启动时控制台会打印 `[MiGu.Server] WebRoot -> dist: ...` 或 `WebRoot -> wwwroot ...`,提示当前使用哪一份产物。
|
||
> 单独启动且既没有跑过 `pnpm build` 也没有跑过 `build-platform-frontend.bat` 时,会看到 SPA fallback 找不到 `index.html`。
|
||
> 仓库根 `build-platform-frontend.bat` 仍可用于「打部署包」场景(把 dist robocopy /MIR 同步到 wwwroot)。
|
||
> SimpleLite 自启 MiGu.Server 时,Program.cs 会从 `bin\<Config>\net8.0\` 沿目录向上找 dist;
|
||
> 找到则使用源码区 dist,找不到则使用 bin 同级的 wwwroot——两种启动方式共用同一份前端产物。
|
||
|
||
## 与前端联调
|
||
|
||
- 开发模式(前端在 Simple 仓库):
|
||
- 前端:`cd ../Simple/frontends && pnpm dev`(`:5173`),Vite 代理 `/api` 至 `http://127.0.0.1:8080`;
|
||
- 后端:`cd MiGu.Server && dotnet run`(`:8080`);
|
||
- 浏览器访问 `http://localhost:5173/login`。
|
||
- 生产/同源模式(本仓库 `wwwroot/`):
|
||
- 默认使用 `MiGu.Server/wwwroot/`(已随仓库提交构建产物);
|
||
- 若上级目录存在 `frontends/apps/simple-platform-vue/dist/`,Program.cs 会优先挂 dist;
|
||
- 浏览器访问 `http://localhost:8080/login` 等路径由 vue-router 解析。
|
||
|
||
## YARP 与 SimpleLite
|
||
|
||
YARP 路由配置见 `appsettings.json`:
|
||
|
||
```json
|
||
{
|
||
"ReverseProxy": {
|
||
"Routes": {
|
||
"sl-route": { "Match": { "Path": "/api/sl/{**catch-all}" }, "ClusterId": "sl-cluster" },
|
||
"vrender-route": { "Match": { "Path": "/vr/{**catch-all}" }, "ClusterId": "vrender-cluster" }
|
||
},
|
||
"Clusters": {
|
||
"sl-cluster": { "Destinations": { "sl1": { "Address": "http://127.0.0.1:8222/" } } },
|
||
"vrender-cluster": { "Destinations": { "vr1": { "Address": "http://127.0.0.1:8223/" } } }
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
- `/api/sl/ops/{execute,audits}` 在本工程被 `OpsController` 显式接住(更具体的路由),用于占位测试;
|
||
- 其他 `/api/sl/*` 由 YARP 透传到 SimpleLite `:8222`,SimpleLite 未启时会得到 502/连接被拒。
|
||
|
||
## iframe 嵌入 webVRender 的两种方式
|
||
|
||
1. **直连**(默认):前端 iframe 指向 `http://localhost:8223/?scope=...&token=...&ro=...`,跨源;
|
||
2. **同源代理**(可选):iframe 指向 `http://localhost:8080/vr/?scope=...`,由本工程 YARP 反代到 8223,
|
||
可规避 X-Frame-Options 等限制。前端可通过 `Workspace3D` 组件的 `host` prop 传 `localhost:8080/vr` 切换。
|
||
|
||
## 相关文档
|
||
|
||
- [ARCHITECTURE.md](ARCHITECTURE.md) — v1.6 总体架构(§4 进程拓扑、§6.3 YARP 配置、§9 配置中心、§10 交互序列、§17 视觉规范)
|
||
- [(见 Simple 仓库)frontends/README.md]((见 Simple 仓库)frontends/README.md) — 前端启动与联调说明(含「迷毂」品牌与紫色主题约定)
|