# Alga PSA Extension System (Enterprise Overview)

This document specifies the Enterprise Edition (EE) extension architecture. It is a v2-only system featuring out-of-process execution, content-addressed signed bundles, a component-model Runner that executes `componentize-js` artifacts, and iframe-only UI delivery served by the Runner.

## Goals
- No tenant code executes in the core app process
- Per-tenant isolation across compute, storage, and egress
- Signed, content-addressed bundles with verified provenance (sha256:…)
- Capability-based host APIs, quotas, and auditable execution

## Architecture

1) Runner Service (Rust + Wasmtime)
- Executes extension handlers as Wasmtime **components** generated via `componentize-js` + `@alga-psa/extension-runtime`
- Enforces memory/time/concurrency limits
- Exposes a minimal set of namespaced host APIs (alga.*) for storage, http, secrets, logging, and metrics
- Provides additional capability providers (e.g., ui proxy) based on install-scoped grants
- Hosts static UI assets for iframe delivery at ${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/[...]

2) Registry & Bundles
- Registry stores extensions, versions, and metadata (content_hash, signature, runtime) plus tenant install configuration (`tenant_extension_install_config`) and sealed secret envelopes (`tenant_extension_install_secrets`)
- Bundles are immutable, content-addressed artifacts in object storage
- Signatures are verified on publish/install and on load, against a configured trust bundle

3) API Gateway (Next.js)
- Route: `/api/ext/[extensionId]/[[...path]]`
- Resolves tenant install via [installConfig](../../../server/src/lib/extensions/installConfig.ts) → version/content hash → config + provider grants → secret envelope
- Proxies requests to Runner `POST /v1/execute` with strict header/size/time policies and quotas, attaching `config`, `providers`, and `secret_envelope` in the body
- Reference scaffold: [server/src/app/api/ext/[extensionId]/[[...path]]/route.ts](../../../server/src/app/api/ext/%5BextensionId%5D/%5B%5B...path%5D%5D/route.ts)
- Manifest endpoint matching is **not enforced** today; it is advisory. Enforcement decision is tracked in [2025-11-12 plan](../plans/2025-11-12-extension-system-alignment-plan.md#workstream-a-%E2%80%94-gateway--registry).

4) UI Delivery (Iframe-Only, served by Runner)
- Static UI assets are served by the Runner at ${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/[...]; the Next.js `ext-ui` route only gates/redirects when rust-host mode is enabled.
- The host constructs the iframe src via [buildExtUiSrc()](../../../server/src/lib/extensions/ui/iframeBridge.ts:38) and bootstraps via [bootstrapIframe()](../../../server/src/lib/extensions/ui/iframeBridge.ts:45)
- Client SDK (@alga/extension-iframe-sdk) provides auth, navigation bridge, and theme token integration
- UI kit (@alga/ui-kit) offers accessible, themed components

5) Observability & Policy
- Structured execution logs correlated to requests/events
- Prometheus metrics (duration, memory, fuel, egress bytes, errors)
- Per-tenant/per-extension quotas and egress allowlists

## Data Model (Initial)
- extension_registry, extension_version, extension_bundle
- tenant_extension_install, extension_event_subscription
- extension_execution_log, extension_quota_usage

## Request Flow (HTTP)
1. Client calls `/api/ext/{extensionId}/{...}` in the host app (iframe or API consumer).
2. Gateway resolves the tenant install config (content hash, version, providers, config map, sealed secret envelope).
3. Gateway filters headers/body, assembles `{context, http, limits, config, providers, secret_envelope}`, and calls Runner `POST /v1/execute`.
4. Runner fetches/verifies the component by `content_hash`, decrypts secrets when permitted, executes the handler, and returns `{status, headers, body_b64}`.
5. Gateway maps the response to the client with header allowlists and optional config/secrets version headers.

## Manifest v2 Summary
Manifest v2 is the canonical specification for extensions:
- runtime: e.g., `wasm-js@1` (the `componentize-js` pipeline output)
- capabilities: least-privilege host APIs requested (storage, http, secrets, etc.)
- api.endpoints: declare HTTP entrypoints (used for docs/UX today; enforcement work tracked in [Plan A4](../plans/2025-11-12-extension-system-alignment-plan.md))
- ui.iframe: iframe entry HTML and asset mapping; UI is served by Runner using content-addressed paths
- ui.hooks: host integration points such as adding menu entries that launch a full-page iframe; designed to expand for tabs and named placeholders
- precompiled and assets: bundle metadata including sha256 content hash and signatures

See full schema: [manifest_schema.md](manifest_schema.md)

## Security Highlights
- No dynamic importing of tenant JS into the host
- Capability-based host API; deny-by-default egress
- Signature verification and content hashing across the bundle lifecycle
- Iframe sandboxing and origin validation aligned with RUNNER_PUBLIC_BASE

## Runner: responsibilities and integration
The Runner is the execution and static asset host for the EE architecture:
- Executes WASM components out-of-process with isolation and quotas (Rust + Wasmtime Component APIs)
- Hosts static UI assets by immutable content hash; the host builds iframe src via [buildExtUiSrc()](../../server/src/lib/extensions/ui/iframeBridge.ts:38) and initializes via [bootstrapIframe()](../../server/src/lib/extensions/ui/iframeBridge.ts:45)
- Provides HTTP interface for handler execution (`POST /v1/execute`) called by the API Gateway. Gateway scaffold: [server/src/app/api/ext/[extensionId]/[[...path]]/route.ts](../../../server/src/app/api/ext/%5BextensionId%5D/%5B%5B...path%5D%5D/route.ts)
- Implements host capabilities including HTTP egress, storage KV, secrets, logging, metrics, and the UI proxy (`alga.ui_proxy`) with enforcement driven by install-level providers.
- Emits live debug events to Redis Streams when `RUNNER_DEBUG_REDIS_URL` is configured; EE consumes these via `/api/ext-debug/stream`.
- Signature and provenance enforcement integrate with Registry v2 services. Registry scaffold: [ExtensionRegistryServiceV2](../../server/src/lib/extensions/registry-v2.ts:48)

Runner-related configuration (host environment):
- `RUNNER_BASE_URL`: internal URL used by the Gateway to call POST /v1/execute
- `RUNNER_PUBLIC_BASE`: public base used to construct ext-ui iframe src
- `EXT_GATEWAY_TIMEOUT_MS`: gateway → runner request timeout
- `SIGNING_TRUST_BUNDLE`: path or inline bundle of trusted public keys/certificates for signature verification
- `RUNNER_DEBUG_REDIS_URL`, `RUNNER_DEBUG_REDIS_STREAM_PREFIX`, `RUNNER_DEBUG_REDIS_MAXLEN`: enable Redis-backed debug streaming
- `UI_PROXY_BASE_URL`, `UI_PROXY_AUTH_KEY`, `UI_PROXY_TIMEOUT_MS`: configure the runner-side UI proxy capability

See detailed Runner doc: [runner.md](runner.md)

## Endpoint and UI delivery correctness
- All extension API calls traverse `/api/ext/[extensionId]/[[...path]]` and are proxied to Runner `/v1/execute`. Enforcement of manifest endpoint lists is TBD (see [plan](../plans/2025-11-12-extension-system-alignment-plan.md)).
- UI assets are served by Runner only, at ${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/[...]; there is no Next.js route for ext-ui

## Live Debugging
- Runner emits structured `ExtDebugEvent` entries (stdout/stderr/log) into Redis Streams when debug streaming is enabled.
- EE exposes `/api/ext-debug/stream` (Server-Sent Events) and a UI at `/msp/extensions/[extensionId]/debug` to authorized tenant operators.
- Capability gating, session TTLs, and audit logging are tracked in [Workstream B](../plans/2025-11-12-extension-system-alignment-plan.md#workstream-b-%E2%80%94-runner--debug-stream).

## References
- [Implementation Plan](implementation_plan.md)
- [Manifest v2](manifest_schema.md)
- [API Routing Guide](api-routing-guide.md)
- [Security & Signing](security_signing.md)
- [Development Guide](development_guide.md)
- [Runner Service](runner.md)
