下线运营总览幽灵页,补 ExpandKeysForScope / PlatformToMonitor,同步导航与角色配置 UI。 Co-authored-by: Cursor <cursoragent@cursor.com>
MiGu.Server
「迷毂 · 智能调度平台」的后端骨架(ASP.NET Core 8 + YARP)。 对应 ARCHITECTURE.md v1.6 §1.1 中提到的「Platform 管理端」后端可执行文件。
会话 N+1(启动反转):现在
MiGu.Server.exe是主入口。 用户先启动 MiGu.Server,浏览器登录页选择「启动模式」(本地+Web / 仅Web), 后端AuthController.Login调用Simple3Launcher.MaybeStart(launchMode)按所选模式拉起Simple3.exe, 通过--display-mode=web|web+local透传给 Simple3 的Configuration.displayMode。工程名
MiGu.Server/ 程序集MiGu.Server.dll保持稳定,仅用户可见前端文案改为「迷毂」。
克隆后首次部署速查(必读)
本仓库为 Migu2.0,已包含预构建的 wwwroot/ 前端,克隆后可直接编译运行 MiGu.Server。
# 1) 编译 MiGu.Server
cd MiGu.Server
dotnet build MiGu.Server.csproj -c Debug
# 2) 启动(登录后按所选模式拉起 Simple3)
dotnet run
# 或:.\bin\Debug\net8.0\MiGu.Server.exe
更新前端:在 Simple 仓库执行 build-platform-frontend.bat,将 frontends/apps/simple-platform-vue/dist/ 同步到本目录 wwwroot/。
配置 Simple3 路径(必读)
配置文件位置(无 Web 界面):
MiGu.Server/appsettings.json→ 搜索"Simple3"节点。
登录页选「本地 + Web / 仅 Web」后,后端在此配置的路径拉起Simple3.exe。
启动后可在浏览器打开http://localhost:8080/api/health/simple3查看路径是否解析成功。
登录成功后,MiGu.Server 会按所选启动模式拉起 Simple3.exe。默认已在 appsettings.json 写好与 Simple 仓库并列的相对路径;开发机可用 appsettings.Development.json 覆盖为绝对路径。
本机开发(与 Simple 仓库并列)
仓库默认已在 appsettings.Development.json 中写好:
"Simple3": {
"Enabled": true,
"ExecutablePath": "E:\\Work\\Core\\Simple-FR\\Simple\\Simple3\\bin\\Debug\\Simple3.exe",
"WorkingDirectory": "E:\\Work\\Core\\Simple-FR\\Simple\\Simple3\\bin\\Debug",
"ProjectionPort": 8222,
"ReadinessTimeoutMs": 8000,
"FollowParent": false
}
请先编译 Simple3(在 Simple 仓库):
cd ..\Simple
dotnet build Simple3\Simple3.csproj -c Debug
若你的 Simple 不在上述绝对路径,可改为相对路径(相对 MiGu.Server 工作目录):
"ExecutablePath": "..\\..\\Simple\\Simple3\\bin\\Debug\\Simple3.exe",
"WorkingDirectory": "..\\..\\Simple\\Simple3\\bin\\Debug"
配置项说明
| 键 | 含义 |
|---|---|
Enabled |
false 时永不拉起 Simple3(只调试平台 UI) |
ExecutablePath |
Simple3.exe 绝对或相对路径;留空则自动探测(见 Launcher/Simple3Options.cs) |
WorkingDirectory |
子进程工作目录;留空则用 exe 所在目录(读写 simple.json / imgui.ini) |
ProjectionPort |
就绪检测端口,默认 8222 |
ReadinessTimeoutMs |
登录后等待 Simple3 WebAPI 就绪的最长时间(毫秒) |
FollowParent |
true 时 MiGu.Server 退出会结束 Simple3;默认 false(两进程独立) |
环境变量覆盖
$env:Simple3__ExecutablePath = "D:\apps\Simple3.exe"
$env:Simple3__WorkingDirectory = "D:\apps"
$env:Simple3__Enabled = "true"
生产 / 合并发布
将 Simple3.exe 与依赖 DLL 放到 MiGu.Server 同目录,并清空 ExecutablePath(走自动探测 ./Simple3.exe),或在 appsettings.Production.json 写死部署路径。
浏览器访问 http://localhost:8080/login:
- 用户名 / 密码(
appsettings.json:Auth.Users默认 admin/admin、ops/ops); - 选 scope(管理员 / 运营);
- 选 Simple3 启动模式:
- 本地 + Web → 透传
--display-mode=web+local,桌面 ImGui 窗口 + 浏览器同时启动; - 仅 Web → 透传
--display-mode=web,只起 WebTerminal,不弹本地窗口;
- 本地 + Web → 透传
- 点登录。
AuthController.Login调用Simple3Launcher.MaybeStart(...)阻塞等 Projection (:8222) 就绪后返回 LoginResponse。
如果只想跑 MiGu.Server 单进程调试(不拉 Simple3),把
appsettings.json:Simple3.Enabled改为false即可。
数据库启动流程
持久层在独立工程 MiGu.DB;Server 通过 PlatformPersistence 接入。
启动顺序(Program.cs)
AddPlatformPersistence(configuration) # 注册 AddMiGuDb + Wms/SimpleFields 等业务服务
│
▼
builder.Build()
│
▼
MigrateMiGuDbAsync() # Schema 初始化 + 可选 IDataMigrator
│
▼
… 其余中间件 …
UseMiddleware<HttpActorContextMiddleware> # 请求级写入 IActorContext(审计戳)
配置(appsettings*.json)
"Database": {
"Provider": "sqlite",
"SchemaMode": "Migrate",
"ApplyDataMigratorsOnStartup": true
},
"ConnectionStrings": {
"Platform": "Data Source=data/platform.db"
}
| 配置项 | 含义 | 取值 |
|---|---|---|
Provider |
数据库种类 | sqlite(默认)/ mysql / npgsql / sqlserver |
SchemaMode |
启动时如何初始化 Schema | 见下表 |
ApplyDataMigratorsOnStartup |
Schema 完成后是否跑数据修补 | true(默认)/ false |
当前仓库约定:
appsettings.json→"SchemaMode": "Migrate"(发版/默认)appsettings.Development.json→"SchemaMode": "EnsureCreated"(本地开发)
也可用环境变量覆盖,例如:$env:Database__SchemaMode = "Migrate"。
SchemaMode 行为
| 值 | 行为 | 适用 |
|---|---|---|
Migrate |
旧库无 __EFMigrationsHistory 时先写 Initial 基线 → MigrateAsync →(可选)DataMigrator |
测试 / 预发 / 生产 |
EnsureCreated |
仅 EnsureCreated(按当前模型建空库),不跑 Migrations →(可选)DataMigrator |
开发期改实体、暂不生成迁移 |
流程图:
SchemaMode = EnsureCreated
→ EnsureCreatedAsync(库已存在则不改结构)
→ IDataMigrator(ApplyDataMigratorsOnStartup=true 时)
SchemaMode = Migrate
→ 程序集无 Migration → EnsureCreated 兜底
→ 否则:基线(如需)→ MigrateAsync
→ IDataMigrator(可选)
开发注意(EnsureCreated):
- 改实体后结构不会自动升级;请删除
MiGu.Server/data/platform.db*再启动。 - 不会写入迁移历史;以后改回
Migrate时,对已有库会走基线再应用 Migrations。
发版注意:
- 现场务必使用
Migrate,并随包带上MiGu.DB/Migrations/Sqlite/。 - 开发期若长期
EnsureCreated改模型,发版前必须对当前模型执行dotnet ef migrations add,再切回Migrate验证;否则空库只会落到旧 Migration,结构落后于代码。 - 从 EnsureCreated 库切到
Migrate:若无 History,启动会把全部 pending Migration 写入基线(假定库已对齐模型 tip)。结构不对齐时应删库重建或手工处理。
相关文档
- 持久层总览与 SchemaMode 摘要:MiGu.DB/README.md
- 如何生成/管理 Migration:MiGu.DB/MIGRATIONS.md
安全须知(生产部署必读)
重要:以下默认值仅供本地开发,切勿原样用于生产环境。
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)。 环境变量示例(__双下划线表示配置层级):$env:Auth__Users__admin__Password = "<强密码>" $env:Jwt__Secret = "<不少于 32 字节的随机串>" $env:Internal__Token = "<随机串>"详见代码审核 ISSUE-03(
Doc/CODE_REVIEW_ISSUES_2026-05-29.md)。Simple3 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.mdRV-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/(Simple3 WebAPI;当前 Simple3 未启 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"字段,登录成功后Simple3Launcher据此拉起子进程; - Simple3 子进程编排:
Launcher/Simple3Launcher.cs幂等 / Stdout 转发 / Windows JobObject 父子绑定 / 端口就绪等待,配置见appsettings.json:Simple3; - 运维白名单网关占位:
/api/sl/ops/execute、/api/sl/ops/audits; - 投影 API 占位:
/api/projection/{sites,tracks,cars,missions}; - 健康检查:
/api/health; - Swagger:开发环境下
/swagger。
能力补充:平台库由 MiGu.DB(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)
独立启动(仅当你不通过 Simple3 自启时)
# 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)。 Simple3 自启 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 与 Simple3
YARP 路由配置见 appsettings.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 透传到 Simple3:8222,Simple3 未启时会得到 502/连接被拒。
iframe 嵌入 webVRender 的两种方式
- 直连(默认):前端 iframe 指向
http://localhost:8223/?scope=...&token=...&ro=...,跨源; - 同源代理(可选):iframe 指向
http://localhost:8080/vr/?scope=...,由本工程 YARP 反代到 8223, 可规避 X-Frame-Options 等限制。前端可通过Workspace3D组件的hostprop 传localhost:8080/vr切换。
相关文档
- ARCHITECTURE.md — v1.6 总体架构(§4 进程拓扑、§6.3 YARP 配置、§9 配置中心、§10 交互序列、§17 视觉规范)
- [(见 Simple 仓库)frontends/README.md]((见 Simple 仓库)frontends/README.md) — 前端启动与联调说明(含「迷毂」品牌与紫色主题约定)
- MiGu.DB/README.md — 持久层框架;MIGRATIONS.md — 生成 Migration 手册
- 本文「数据库启动流程」— SchemaMode / EnsureCreated / Migrate