PSA/ee/docs/plans/extension-system-v2-migration.md
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

261 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Enterprise Extension System v2 Migration Plan (Remove Legacy)
This plan removes the legacy descriptor-based system (never deployed) and finalizes the v2 architecture: API Gateway, iframe-only UI delivery, Manifest v2, and Registry v2. Work is organized into phases with checklists and explicit commit checkpoints to keep the main branch stable.
Status: Completed. All phases executed and guardrails in place.
Key references:
- initializeExtensions(): [ee/server/src/lib/extensions/initialize.ts](ee/server/src/lib/extensions/initialize.ts:5)
- buildExtUiSrc(): [ee/server/src/lib/extensions/ui/iframeBridge.ts](ee/server/src/lib/extensions/ui/iframeBridge.ts:38)
- bootstrapIframe(): [ee/server/src/lib/extensions/ui/iframeBridge.ts](ee/server/src/lib/extensions/ui/iframeBridge.ts:45)
- ExtensionRegistryServiceV2: [ee/server/src/lib/extensions/registry-v2.ts](ee/server/src/lib/extensions/registry-v2.ts:48)
- API Routing Spec Example: [ee/docs/extension-system/api-routing-guide.md](ee/docs/extension-system/api-routing-guide.md)
Terminology and target paths:
- Gateway route: /api/ext/[extensionId]/[[...path]] implemented under [server/src/app/api/ext/[extensionId]/[[...path]]/route.ts](../server/src/app/api/ext/%5BextensionId%5D/%5B%5B...path%5D%5D/route.ts)
- Iframe UI delivery: served by Runner at ${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/[...] (no Next.js route in ee/server)
- Manifest v2 validator: [ee/server/src/lib/extensions/schemas/manifest-v2.schema.ts](ee/server/src/lib/extensions/schemas/manifest-v2.schema.ts)
- v2-only exports: [ee/server/src/lib/extensions/index.ts](ee/server/src/lib/extensions/index.ts)
---
## Phase 0 — Branch setup and inventory
- [x] Create feature branch for the migration
- Suggested: `git checkout -b ee/ext-system-v2-only`
- [x] Confirm legacy artifacts to remove (see detailed lists in Phase 2)
Commit checkpoint:
- Commands:
- `git add -A`
- `git commit -m "chore(ext): start v2-only migration branch and inventory legacy artifacts"`
---
## Phase 1 — Add v2 primitives (before deleting legacy)
1) API Gateway route scaffold
- [x] Create Next.js route handler: [ee/server/src/app/api/ext/[extensionId]/[...path]/route.ts](ee/server/src/app/api/ext/%5BextensionId%5D/%5B...path%5D/route.ts)
- [x] Implement handler for GET/POST/PUT/PATCH/DELETE:
- [x] Resolve tenant context from auth/session (RBAC check)
- [x] Resolve install → active version → content_hash
- [x] Load manifest v2 for that version and match endpoint by method+path
- [x] Normalize and proxy to Runner: `POST ${RUNNER_BASE_URL}/v1/execute` (timeout `EXT_GATEWAY_TIMEOUT_MS`)
- [x] Header allowlist/strip and response mapping per spec: [ee/docs/extension-system/api-routing-guide.md](ee/docs/extension-system/api-routing-guide.md)
- [x] Correlate with `x-request-id`
- [x] Unit tests:
- [x] Endpoint resolution (method+path)
- [x] Header policy (allowlist/strip)
- [x] Timeout/error mapping (404/413/502/504)
2) Runner UI delivery confirmation
- [x] Confirm Runner serves iframe UI assets at `${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/[...]` (content-addressed, immutable)
- [x] Ensure host URL builder parity: [buildExtUiSrc()](ee/server/src/lib/extensions/ui/iframeBridge.ts:38) constructs correct src for Runner public base
- [x] Document and enforce immutable cache headers at Runner; only static file types are served
- [x] Do NOT implement a Next.js ext-ui route in ee/server; the Runner is the sole static UI host
3) Manifest v2 validator/types
- [x] Add manifest v2 schema: [ee/server/src/lib/extensions/schemas/manifest-v2.schema.ts](ee/server/src/lib/extensions/schemas/manifest-v2.schema.ts)
- Fields: `name`, `publisher`, `version`, `runtime`, `capabilities[]`, `ui.type='iframe'` with `entry`, `api.endpoints[]` (method/path/handler), `precompiled`, `assets`, `sbom`
- [x] Wire v2 validation into registry install/publish flow (placeholder until Phase 1.4)
- [x] Export validator/types from index: [ee/server/src/lib/extensions/index.ts](ee/server/src/lib/extensions/index.ts)
4) Minimal Registry v2 wiring to unblock Gateway
- [x] Implement DB-backed methods in ExtensionRegistryServiceV2: [ee/server/src/lib/extensions/registry-v2.ts](ee/server/src/lib/extensions/registry-v2.ts:48)
- [x] createRegistryEntry, listRegistryEntries, getRegistryEntryByName
- [x] addVersion (persist `runtime`, `api`, `ui`, `capabilities`)
- [x] attachBundle (persist `content_hash`, `signature`, `precompiled`)
- [x] Add install resolution helpers (tenant → install → active version + content_hash)
- [x] Signature shape validation stub; store signature (full verification in Phase 3)
5) v2-first exports
- [x] Update index to export only v2 interfaces and helpers (leave legacy in place for now, but stop re-exporting where possible):
- Stop new consumers from importing legacy modules
- Export: Manifest v2 validator/types, ExtensionRegistryServiceV2, iframeBridge
- File: [ee/server/src/lib/extensions/index.ts](ee/server/src/lib/extensions/index.ts)
Commit checkpoint:
- Commands:
- `git add ee/server/src/app/api/ext ee/server/src/app/ext-ui ee/server/src/lib/extensions/schemas/manifest-v2.schema.ts ee/server/src/lib/extensions/index.ts ee/server/src/lib/extensions/registry-v2.ts`
- `git commit -m "feat(ext-v2): add gateway scaffold, ext-ui route, manifest v2 validator, minimal registry wiring"`
---
## Phase 2 — Remove legacy codepaths and fallbacks
A) Remove descriptor-based UI pipeline and security whitelist
- [x] Delete descriptor renderer and descriptors:
- [ee/server/src/lib/extensions/ui/DescriptorRenderer.tsx](ee/server/src/lib/extensions/ui/DescriptorRenderer.tsx)
- [ee/server/src/lib/extensions/ui/descriptors](ee/server/src/lib/extensions/ui/descriptors)
- [x] Delete pages/tabs/navigation legacy UI:
- [ee/server/src/lib/extensions/ui/pages](ee/server/src/lib/extensions/ui/pages)
- [ee/server/src/lib/extensions/ui/tabs](ee/server/src/lib/extensions/ui/tabs)
- [ee/server/src/lib/extensions/ui/navigation](ee/server/src/lib/extensions/ui/navigation)
- [x] Delete security whitelist:
- [ee/server/src/lib/extensions/security/propWhitelist.ts](ee/server/src/lib/extensions/security/propWhitelist.ts)
- [x] Remove re-exports from:
- [ee/server/src/lib/extensions/ui/index.ts](ee/server/src/lib/extensions/ui/index.ts)
B) Remove renderer, routers, server actions, hooks, dev/mock route
- [x] Replace/remove legacy renderer:
- [ee/server/src/lib/extensions/ui/ExtensionRenderer.tsx](ee/server/src/lib/extensions/ui/ExtensionRenderer.tsx)
- Migrate any callsites to iframe embed flow (using buildExtUiSrc() + bootstrapIframe())
- [x] Delete legacy router:
- [ee/server/src/lib/extensions/routing/ExtensionRouter.tsx](ee/server/src/lib/extensions/routing/ExtensionRouter.tsx)
- [x] Delete server action for descriptor loads:
- [ee/server/src/lib/actions/extension-actions/extensionActions.ts](ee/server/src/lib/actions/extension-actions/extensionActions.ts)
- [x] Delete dev/mock hook:
- [ee/server/src/hooks/useExtensions.ts](ee/server/src/hooks/useExtensions.ts)
- [x] Delete dev/mock API route:
- [ee/server/src/app/api/extensions/route.ts](ee/server/src/app/api/extensions/route.ts)
C) Remove MSP descriptor-based page and replace with iframe page (or remove)
- [x] Delete or replace page:
- [ee/server/src/app/msp/extensions/[extensionId]/[...path]/page.tsx](ee/server/src/app/msp/extensions/%5BextensionId%5D/%5B...path%5D/page.tsx)
- If retained, render a sandboxed iframe using buildExtUiSrc() and bootstrapIframe()
D) Remove legacy schemas/validators/types
- [x] Delete legacy manifest schema and extension points:
- [ee/server/src/lib/extensions/schemas/manifest.schema.ts](ee/server/src/lib/extensions/schemas/manifest.schema.ts)
- [ee/server/src/lib/extensions/schemas/extension-points.schema.ts](ee/server/src/lib/extensions/schemas/extension-points.schema.ts)
- [x] Delete legacy validator helpers:
- [ee/server/src/lib/extensions/validator.ts](ee/server/src/lib/extensions/validator.ts)
- [x] Prune v1 UI component types from:
- [ee/server/src/lib/extensions/types.ts](ee/server/src/lib/extensions/types.ts)
- Remove `ExtensionComponentType` and Tab/Navigation/Dashboard/CustomPage types; keep only shared DB models still used
E) Delete prototypes/POCs
- [x] Remove disregard prototype:
- [ee/server/src/disregard-pgs/ext/[...path].tsx](ee/server/src/disregard-pgs/ext/%5B...path%5D.tsx)
Commit checkpoint:
- Commands:
- `git rm -r ee/server/src/lib/extensions/ui/descriptors ee/server/src/lib/extensions/ui/pages ee/server/src/lib/extensions/ui/tabs ee/server/src/lib/extensions/ui/navigation`
- `git rm ee/server/src/lib/extensions/ui/DescriptorRenderer.tsx ee/server/src/lib/extensions/security/propWhitelist.ts`
- `git rm ee/server/src/lib/extensions/routing/ExtensionRouter.tsx ee/server/src/lib/actions/extension-actions/extensionActions.ts ee/server/src/hooks/useExtensions.ts`
- `git rm ee/server/src/app/api/extensions/route.ts ee/server/src/app/msp/extensions/[extensionId]/[...path]/page.tsx`
- `git rm ee/server/src/lib/extensions/schemas/manifest.schema.ts ee/server/src/lib/extensions/schemas/extension-points.schema.ts ee/server/src/lib/extensions/validator.ts`
- `git rm ee/server/src/disregard-pgs/ext/[...path].tsx`
- Edit and stage `ee/server/src/lib/extensions/ui/index.ts`, `ee/server/src/lib/extensions/ui/ExtensionRenderer.tsx`, `ee/server/src/lib/extensions/types.ts`
- `git add -A`
- `git commit -m "refactor(ext-v2): remove legacy descriptor-based UI, schemas, routes, and fallbacks"`
---
## Phase 3 — Finalize v2 enforcement and security
- [x] Implement full signature verification on bundle publish/install:
- Trust bundle env (e.g., `SIGNING_TRUST_BUNDLE`)
- Verify detached signature and `content_hash` on install and load
- [x] Enforce capability grants on Runner invocation (gateway enforces)
- [x] Enforce egress allowlists for http.fetch
- [x] Harden gateway limits and timeouts per spec
Commit checkpoint:
- `git add -A && git commit -m "feat(ext-v2): signature verification, capability grants, egress allowlists, gateway limits"`
---
## Phase 4 — Docs to v2-only (remove legacy references and interim banners)
- [x] Rewrite the following to present v2 as the only system:
- [ee/docs/extension-system/overview.md](ee/docs/extension-system/overview.md)
- [ee/docs/extension-system/manifest_schema.md](ee/docs/extension-system/manifest_schema.md)
- [ee/docs/extension-system/api-routing-guide.md](ee/docs/extension-system/api-routing-guide.md)
- [ee/docs/extension-system/serving-system.md](ee/docs/extension-system/serving-system.md)
- [ee/docs/extension-system/security_signing.md](ee/docs/extension-system/security_signing.md)
- [ee/docs/extension-system/development_guide.md](ee/docs/extension-system/development_guide.md)
- [x] Remove status banners and any legacy descriptor references
- [x] Update or remove example docs under [ee/docs/examples](ee/docs/examples) that rely on descriptors
Commit checkpoint:
- `git add -A && git commit -m "docs(ext-v2): finalize v2-only docs; remove legacy references and interim banners"`
---
## Phase 5 — Guardrails and repo-wide cleanup
- [x] Global search to ensure no references remain:
- Patterns: `"descriptors/pages/"`, `"DescriptorRenderer"`, `"TabExtensionSlot"`, `"NavigationRegistry"`, `"PageRegistry"`, `"loadExtensionDescriptor"`
- [x] Add ESLint custom rule (eslint-plugin-custom-rules) to ban imports from:
- `ee/server/src/lib/extensions/ui/descriptors/*`
- `ee/server/src/lib/extensions/ui/pages/*`
- `ee/server/src/lib/extensions/ui/tabs/*`
- `ee/server/src/lib/extensions/ui/navigation/*`
- `ee/server/src/lib/extensions/security/propWhitelist.ts`
- `ee/server/src/lib/extensions/schemas/manifest.schema.ts`
- `ee/server/src/lib/extensions/validator.ts`
- [x] CI grep step to fail on banned paths (defense-in-depth)
Commit checkpoint:
- `git add -A && git commit -m "chore(ext-v2): add lint/CI guardrails to prevent legacy imports"`
---
## Phase 6 — Tests and verification
Unit tests:
- [x] Manifest v2 validator accept/reject test matrix
- [x] Gateway header allowlist/strip, path resolution, timeouts/errors
Integration (with mocked Runner /v1/execute):
- [x] 200/404/413/502/504 response mappings and headers
- [x] Correlation IDs propagated
- [x] ext-ui route serves by `content_hash` with immutable caching and correct MIME types
- URL parity with builder: [ee/server/src/lib/extensions/ui/iframeBridge.ts](ee/server/src/lib/extensions/ui/iframeBridge.ts)
Build and typing:
- [x] `tsc` clean
- [x] `next build` passes
- [x] Lint passes with new guardrails
Commit checkpoint:
- `git add -A && git commit -m "test(ext-v2): unit+integration tests; build/lint/type verification"`
---
## Post-migration: Developer guidance and examples
- [x] Update example extension template to v2 layout
- WASM handlers, iframe UI app, manifest v2, signed bundle
- Demonstrate gateway calls from UI to `/api/ext/{extensionId}/...`
- [x] Remove any descriptor JSON assets from examples
- [x] Reference SDKs where applicable:
- `@alga/extension-iframe-sdk` and `@alga/ui-kit` (document usage and minimal example)
Commit checkpoint:
- `git add -A && git commit -m "docs/examples(ext-v2): v2 example extension; remove legacy descriptor assets"`
---
## Notes and risks
- Breakage risk stems from lingering imports/types; mitigated by phased deletes, repo-wide searches, and ESLint/CI bans.
- Keep the gateways Runner request/response mapping in a dedicated helper to accommodate Runner interface evolution.
- Ensure server ext-ui route path composition mirrors buildExtUiSrc() to avoid drift.
---
## Appendix A — Quick command snippets
Create branches, add, and commit:
```
git checkout -b ee/ext-system-v2-only
git add -A
git commit -m "message"
```
Grep checks (local preflight):
```
git grep -n "DescriptorRenderer\|descriptors/pages/\|TabExtensionSlot\|NavigationRegistry\|PageRegistry\|loadExtensionDescriptor" -- "ee/server" || true
```
---
## Appendix B — Canonical references
- initializeExtensions(): [ee/server/src/lib/extensions/initialize.ts](ee/server/src/lib/extensions/initialize.ts:5)
- buildExtUiSrc(): [ee/server/src/lib/extensions/ui/iframeBridge.ts](ee/server/src/lib/extensions/ui/iframeBridge.ts:38)
- bootstrapIframe(): [ee/server/src/lib/extensions/ui/iframeBridge.ts](ee/server/src/lib/extensions/ui/iframeBridge.ts:45)
- ExtensionRegistryServiceV2: [ee/server/src/lib/extensions/registry-v2.ts](ee/server/src/lib/extensions/registry-v2.ts:48)
- API Routing Spec Example: [ee/docs/extension-system/api-routing-guide.md](ee/docs/extension-system/api-routing-guide.md)