Files
黄兆尉andCursor c9e835aaf7 运维网关支持按车辆配置方法真实下发,并按用户过滤审计。
新增 ops.car.execute 路径与前端运维操作/选中面板联动。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 17:50:34 +08:00
..

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

  1. 用户名 / 密码(appsettings.json:Auth.Users 默认 admin/admin、ops/ops);
  2. 选 scope(管理员 / 运营);
  3. Simple3 启动模式
    • 本地 + Web → 透传 --display-mode=web+local,桌面 ImGui 窗口 + 浏览器同时启动;
    • 仅 Web → 透传 --display-mode=web,只起 WebTerminal,不弹本地窗口;
  4. 点登录。AuthController.Login 调用 Simple3Launcher.MaybeStart(...) 阻塞等 Projection (:8222) 就绪后返回 LoginResponse。

如果只想跑 MiGu.Server 单进程调试(不拉 Simple3),把 appsettings.json:Simple3.Enabled 改为 false 即可。

数据库启动流程

持久层在独立工程 MiGu.DBServer 通过 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(库已存在则不改结构)
  → IDataMigratorApplyDataMigratorsOnStartup=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)。结构不对齐时应删库重建或手工处理。

相关文档

安全须知(生产部署必读)

重要:以下默认值仅供本地开发,切勿原样用于生产环境。

  • appsettings.json:Auth.Users 内置 admin/adminops/ops 为弱口令演示账号;
  • appsettings.json:Jwt.SecretInternal.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-03Doc/CODE_REVIEW_ISSUES_2026-05-29.md)。

Simple3 8222 内部 APIRV-04:默认 simple.json:platform.allowLoopbackBypass=true,本机回环请求免 token多租户 / 共享主机的生产环境建议设为 false,强制所有请求携带 X-Platform-Internal-Token(配合 platform.internalTokenMiGu.Server/data/.internal-token)。详见复审 Doc/CODE_REVIEW_WEEK_2026-05-29.md RV-04。

能力清单(本轮)

  • Kestrel 监听 :8080HTTP);
  • 静态托管:启动时自动探测 WebRoot ——
    • 开发模式:仓库内 frontends/apps/simple-platform-vue/dist/ 存在则直接挂为 WebRootpnpm 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 + EffectivePermissionsLoginRequest 新增 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.DBEF 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/.../distassets/ 与 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 代理 /apihttp://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 :8222Simple3 未启时会得到 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 — 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