# CLAUDE.md 本仓库是一个 Cargo workspace,承载两个 PLC 上位机应用,共享一个平台核心库与一套前端基础设施。 ## 两个应用 - **投煤控制系统** — crate `app_feeder_distributor`,前端 `web/feeder/`,默认端口 `60309`,单实例锁名 `PLCControl.FeederDistributor`(约定)。业务模型是 `control unit + run/stop/acc/bl 时长`。 - **隧道窑运转系统** — crate `app_operation_system`,前端 `web/ops/`,默认端口 `3100`,单实例锁名 `PLCControl.OperationSystem`。业务模型是 `工位 + 流程段(segment) + 步骤 + 联锁 + 完成确认`,不要套用 feeder 的 unit 模型。 - 共享核心库 `plc_platform_core`:config / db / connection(OPC UA) / event / websocket / service / 平台 handler。 两个应用页签完全一致:**运行监控 / 应用配置 / 平台配置**,布局也对齐——**系统事件在「运行监控」**,**实时日志(SSE)在「平台配置」**。feeder 的「应用配置」是控制单元,ops 的是段/工位配置。 ## 前端架构(关键、易踩坑) - `/ui` 路由 = `ServeDir(应用目录).fallback(ServeDir("web/core"))`(见 `plc_platform_core/src/http.rs::static_ui_routes`)。**物理放在 `web/core/` 的文件,对两个应用都暴露在相同的 `/ui/*` URL**。所以共享前端无需改 import 路径,只要移动文件位置。 - **共享平台 JS 在 `web/core/js/platform/`**(api/dom/state/roles/sources/points/equipment/events/chart/docs/platform-config)。放子目录是有意为之:`web/ops/js/` 自带 **同名但不同内容**的 `api.js`、`dom.js`(导出 `segmentApi`/`el`,而非 `apiFetch`/`dom`)。若把共享模块放 `web/core/js/` 顶层,会被 ops 本地同名文件 shadow。放 `js/platform/` 子目录后两个应用都回退到 core,得到单一实例。 - 平台配置页的事件绑定 / 初始化 / 数据加载统一在 `web/core/js/platform/platform-config.js`:`bindPlatformConfigEvents()` / `initPlatformConfigUi()` / `loadPlatformConfig()`,全部 null-guard(各应用只含部分面板)。feeder 的 `app.js` 和 ops 的 `views.js` 都调用它,**不要再复制这套逻辑**。 - `web/core/js/platform/events.js` 在**模块加载时**就给 `dom.eventList` 加 scroll 监听 → 凡引入平台 JS(events.js)的页面,DOM 里必须有 `#eventList`(`logs-panel.html`,现放在「运行监控」),否则 import 链在加载期就崩。 - 实时日志(SSE `/api/logs/stream` → `#logView`)在共享的 `web/core/js/platform/log-stream.js`(`startLogs`/`stopLogs`),feeder 与 ops 的「平台配置」都用它。 - HTML 是分片 `data-partial`,由各 `index.js` 先加载完所有 partial 再 `import('./app.js')`;core 的 `dom.js` 在 import 期 `byId`,依赖这个加载顺序。 - 静态文件 ServeDir 直接读磁盘,**改 JS/HTML/CSS 不用重新编译**,刷新即可;改 Rust 才需重启进程(注意单实例锁,旧进程不退会占锁)。 ## 后端要点 - ops 的 router 已 `merge(plc_platform_core::handler::platform_routes())`,平台 CRUD(source/point/equipment/tag/page)两个应用共用。`/api/event` 是 **ops 自己的** `runtime_routes`,不在 platform_routes 里。 - **数据库迁移不自动执行**(`db.rs` 注释)。首次启动前手动跑 `migrations/`:`sqlx migrate run --source migrations`。 - 事件类型用命名空间前缀:`platform.*` / `feeder.*` / `ops.*`。 ## 构建 / 运行 ```powershell cargo build -p app_operation_system # 或 -p app_feeder_distributor cargo run -p app_operation_system # 开发态 ``` ops 调试用环境变量:`OPS_SEED_TEMPLATES=1`(写入 12 段+11 工位骨架)、`SIMULATE_PLC=1`(自动回写确认信号,无 PLC 也能跑通段)。详见 `run.md`。 ## 文档 - 运转系统方案:`docs/运转系统实现方案.md` - 双应用共享核心设计:`docs/superpowers/specs/2026-04-14-dual-app-shared-core-design.md` - API:`docs/api-feeder.md`、`docs/api-ops.md`