# Remote WebUI Bundle Loading

GovOPlaN WebUI modules normally ship through the core WebUI package graph:
install a tagged npm/git dependency, run `npm install`, rebuild the shell, and
restart or reload the served assets. Remote WebUI bundles are an experimental
future path for controlled deployments where a backend-enabled module is not in
the local WebUI package graph and the operator wants the shell to load its
frontend without rebuilding core.

This design defines the target guardrails. The current rebuild/reload path
remains the default production path.

## Current Rebuild Path

The supported release path is:

1. Install or remove backend and WebUI package dependencies through the trusted
   installer CLI/daemon.
2. Snapshot package state before mutation.
3. Run `npm install` and optionally `npm run build`.
4. Restart or reload the served WebUI assets.
5. Use installer rollback if package apply, restart, or health checks fail.

Strengths:

- package manager and lockfile semantics stay conventional
- CSP can stay strict because all code is served as built assets
- rollback restores package files and lockfiles
- local development uses sibling workspace dependencies naturally

Costs:

- frontend changes require a rebuild/reload
- hot enabling a module with frontend code is not possible in the running shell
- failed rebuilds happen at install time, not at lazy module-load time

## Remote Bundle Path

Remote loading is only for modules that are enabled by the backend and absent
from `virtual:govoplan-installed-modules`. The backend manifest exposes:

- `FrontendModule.asset_manifest`
- `asset_manifest_integrity`
- `asset_manifest_signature`
- `asset_manifest_public_key_id`
- `asset_manifest_contract_version`

The WebUI shell fetches the asset manifest, verifies manifest integrity and/or
signature, validates the manifest contract, fetches the entry bundle, verifies
the entry integrity, imports the bundle, validates the exported
`PlatformWebModule`, and applies backend metadata before registering routes,
navigation, and UI capabilities.

Unsigned and unhashed manifests are skipped. Entries without integrity are
skipped. A module id mismatch is skipped.

## Asset Manifest Contract

Contract version `1`:

```json
{
  "contractVersion": "1",
  "moduleId": "files",
  "entry": "./files-webui.remote.js",
  "entryIntegrity": "SHA-256-<base64-or-hex-digest>",
  "moduleExport": "default"
}
```

The backend manifest carries the manifest-level trust metadata. The remote
asset manifest carries the concrete entry URL and entry digest.

## Compatibility Checks

Before a remote bundle is accepted:

- backend module must be enabled
- local WebUI module with the same id must be absent
- manifest contract must be supported by the shell
- manifest `moduleId`, exported module `id`, and backend module id must match
- backend metadata remains authoritative for label, version, dependencies,
  nav, and runtime UI capability exposure
- future contract versions must declare required shell capabilities so old
  shells fail closed

Remote bundles must not broaden backend permissions. They can only contribute
routes/nav/capabilities that the backend metadata and existing permission
checks allow.

## CSP

The current implementation imports verified entry bytes through a blob URL. A
production CSP for this mode must explicitly allow:

- `connect-src` for the approved asset-manifest and bundle origins
- `script-src` for `blob:` only when remote loading is enabled
- no `unsafe-inline` requirement for remote modules

If an installation cannot allow `blob:` scripts, the follow-up implementation
should use signed same-origin module assets with static URLs instead of blob
imports. Remote loading must be disableable by configuration so strict-CSP
deployments can keep the rebuild path only.

## Cache Invalidation

The shell cache key is:

```text
<module-id>:<asset-manifest-url>:<backend-module-version>
```

Release catalogs should publish immutable manifest and entry URLs or change at
least one cache-key component on every release. Emergency rollback can point the
backend manifest at a previous immutable manifest URL or lower the enabled
module version after the backend package rollback.

Browsers may still cache remote responses. Approved asset servers should use:

- long cache lifetimes only for content-addressed immutable assets
- short cache lifetimes or explicit revalidation for channel/latest manifest
  aliases
- `Cache-Control: no-store` for emergency override manifests

## Rollback

Remote WebUI rollback is metadata rollback, not package-manager rollback:

- if the backend package install rolls back, the previous backend frontend
  metadata returns
- if only remote assets are bad, publish a new manifest URL or revert the
  backend/frontend metadata to the last known good manifest
- failed remote loading must degrade by omitting the remote module frontend,
  not by breaking the shell

Installer run records should eventually include remote asset manifest URLs,
integrity, signature key ids, and load-test results when a plan enables a
remote frontend.

## Local And Development Behavior

Local development should keep using workspace/file dependencies and Vite. Remote
loading is useful for integration testing release artifacts, not for day-to-day
module UI development.

Development deployments may use unsigned catalogs and local asset servers only
when signature/integrity enforcement is intentionally disabled. The remote
loader itself still requires an integrity hash or a verifiable signature.

## Follow-Up Slices

1. Add a server-side remote-bundle policy flag and surface whether remote
   loading is enabled in platform metadata.
2. Add CSP documentation/config generation for strict rebuild-only mode versus
   controlled remote-bundle mode.
3. Add an installer/catalog preflight that validates remote WebUI asset
   manifests and records verified identity in installer run records.
4. Add Playwright coverage for a signed test remote bundle, failed digest, bad
   module id, cache-key refresh, and fallback when the module is unavailable.
5. Add release tooling to emit immutable remote asset manifests with digest,
   signature, key id, and rollback metadata.
