NODEDC_MISSION_CORE/docs/adr/0010-plugin-owned-frontend-...

3.7 KiB

ADR 0010: plugin-owned frontend device workflows

  • Status: accepted
  • Date: 2026-07-17
  • Extends: ADR 0003, ADR 0004 and ADR 0009

Context

The device UI registry already mounted a model-specific device.connection component, but the XGRIDS implementation still lived below apps/control-station/src/device-plugins. Its 600-line connection view mixed BLE discovery, Wi-Fi provisioning, acquisition/replay controls, diagnostics and metrics. The boundary was logical, yet the plugin source and styles were still physically owned by the generic application tree.

Different device families need different enrollment, connection and acquisition workflows. Making those workflows generic would either produce a lowest-common- denominator wizard or restore vendor branches in the Control Station.

Decision

Device-specific operator workflows are frontend plugin contributions. The XGRIDS source, API adapter, runtime provider, observation mapping and scoped CSS are physically located under:

plugins/xgrids-k1/frontend/src/
  plugin.ts
  XgridsK1Connection.tsx
  components/
    K1ProvisioningPipeline.tsx
    K1AcquisitionPipeline.tsx
    K1Diagnostics.tsx
    K1Metrics.tsx

The generic host exposes one reviewed frontend surface through @mission-core/plugin-sdk, implemented by apps/control-station/src/core/device-plugins/frontendSdk.ts. A plugin may use manifest/model/slot contracts, the generic Mission Runtime bridge, React and the NODE.DC UI kit. It may not import Control Station implementation paths.

apps/control-station/src/composition/devicePlugins.ts is the only Core file which imports the concrete XGRIDS frontend. The host owns model selection, safe deactivation, the device.connection slot, navigation, the spatial scene, saved-session UX and global layout. The plugin owns BLE candidates, exact-profile attestation, credentials-in-memory form state, K1 endpoint state, connection instructions and the live/replay acquisition controls.

Plugin CSS is imported with the contribution and scoped below .xgrids-k1-plugin. A plugin cannot add global navigation, route ownership or unscoped global selectors.

Frontend loading remains static and reviewed at build time. This ADR does not introduce arbitrary remote JavaScript, an npm marketplace, signatures or process/browser-realm isolation.

Acceptance gate

The frontend boundary test builds two unrelated synthetic device plugins with different connection components and proves that the unchanged registry resolves the correct component for each model. It also fails when:

  • XGRIDS implementation files return to the generic Control Station source;
  • generic Core files other than the composition root contain XGRIDS/Lixel/K1 implementation knowledge;
  • plugin source imports Control Station implementation paths;
  • provisioning, acquisition, diagnostics or scoped-style modules disappear.

The accepted local gate is 114 frontend unit tests, TypeScript strict checking and a Vite production build. Backend behavior and the physical K1 protocol are unchanged by this source/UI decomposition.

Consequences

A second device family can provide a completely different connection pipeline and UI while reusing the same model catalog, lifecycle transition, observation scene and saved-session host. Adding it requires its own plugin-owned frontend contribution and one reviewed composition import, not edits to App, DeviceWorkspace or generic runtime state.

The remaining isolation gap is deployment-level: frontend contributions are still compiled into one signed application build, and backend plugins still run inside the control-plane process. Signed bundles, compatibility handshake, dynamic loading policy and process/restart containment belong to the supervisor milestone.