- Move source/point/equipment/tag/page handlers from feeder to plc_platform_core
using State<PlatformContext>; feeder re-exports via handler modules
- Keep batch_set_point_value in feeder (requires app-specific write key auth)
- Add PlatformEvent enum and persist_and_broadcast() in core for platform event
persistence to DB + WebSocket broadcast
- Add PlatformContext::emit_event() that handles both sink notification and
async persistence in one call
- Add platform_routes<S>() in core for centralized route registration;
both feeder and ops merge it instead of duplicating route definitions
- Implement FromRef<AppState> for PlatformContext in both apps
- Add FeederPlatformEventSink adapter bridging core events to feeder's
EventManager + ControlRuntimeStore
- Add event namespace prefixes: platform.source.created, feeder.unit.fault_locked, etc.
- Register full platform CRUD routes in ops app
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Four remaining improvements for the dual-app split:
1. Migrate platform handlers (tag/page/source/point/equipment) to core
2. Add event namespace prefixes (platform.*/feeder.*/ops.*)
3. Register platform routes in ops app
4. Ops business logic (pending requirements)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- PlatformContext now holds pool, connection_manager, ws_manager
- bootstrap_platform returns PlatformBuilder for pre-Arc setup
- Feeder AppState embeds PlatformContext (state.platform.pool etc.)
- Ops AppState embeds PlatformContext with real DB connection
- Remove WebSocket type duplication: feeder re-exports from core
- Add subscribe_room/send_to_room/remove_room_if_empty to WebSocketManager
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The web/core, web/feeder, and web/ops directories were mistakenly
committed as deletions. Restore from f8757a7.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clean up old web module files that were superseded by the per-app
split architecture. Includes plan documentation for the migration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Batch equipment-unit assignment is now handled via the "选择设备"
modal in app-config. Remove the batch toolbar, checkbox selection,
and related JS/state from the equipment panel in platform config.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix unit-config-list grid by increasing specificity over .list flex
- Equipment selection modal uses card grid (auto-fill 150px) instead
of one-per-line list
- Widen modal to accommodate card grid
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Unit cards in app-config use CSS grid (auto-fill 260px min) for
compact card layout across the full page
- Each card shows bound equipment tags and a "选择设备" button
- Equipment selection modal allows multi-select with checkboxes,
calls batch set-unit API to bind/unbind, then refreshes
- App-config loads both units and equipments on first switch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Unit cards in app-config use CSS grid with auto-fill columns
- Equipment panel (with batch unit assignment) visible in both
app-config and platform-config views
- App-config loads both units and equipments on first switch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Delete feeder source-panel override (units no longer in platform config)
- Extract buildUnitCard() and render to both unitList and unitConfigList
- Guard null DOM refs for removed unit buttons
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When any equipment's REM signal switches to local mode, fire a dedicated
`unit.rem_local` event (with unit + equipment context) and record it to
the event log. Also fire `unit.rem_recovered` when all REM signals return
to remote. AutoControlStopped is still fired alongside RemLocal when
auto was running at the time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>