Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
14 KiB
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
- buildExtUiSrc(): ee/server/src/lib/extensions/ui/iframeBridge.ts
- bootstrapIframe(): ee/server/src/lib/extensions/ui/iframeBridge.ts
- ExtensionRegistryServiceV2: ee/server/src/lib/extensions/registry-v2.ts
- API Routing Spec Example: 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
- 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
- v2-only exports: ee/server/src/lib/extensions/index.ts
Phase 0 — Branch setup and inventory
- Create feature branch for the migration
- Suggested:
git checkout -b ee/ext-system-v2-only
- Suggested:
- Confirm legacy artifacts to remove (see detailed lists in Phase 2)
Commit checkpoint:
- Commands:
git add -Agit commit -m "chore(ext): start v2-only migration branch and inventory legacy artifacts"
Phase 1 — Add v2 primitives (before deleting legacy)
- API Gateway route scaffold
- Create Next.js route handler: ee/server/src/app/api/ext/[extensionId]/[...path]/route.ts
- Implement handler for GET/POST/PUT/PATCH/DELETE:
- Resolve tenant context from auth/session (RBAC check)
- Resolve install → active version → content_hash
- Load manifest v2 for that version and match endpoint by method+path
- Normalize and proxy to Runner:
POST ${RUNNER_BASE_URL}/v1/execute(timeoutEXT_GATEWAY_TIMEOUT_MS) - Header allowlist/strip and response mapping per spec: ee/docs/extension-system/api-routing-guide.md
- Correlate with
x-request-id
- Unit tests:
- Endpoint resolution (method+path)
- Header policy (allowlist/strip)
- Timeout/error mapping (404/413/502/504)
- Runner UI delivery confirmation
- Confirm Runner serves iframe UI assets at
${RUNNER_PUBLIC_BASE}/ext-ui/{extensionId}/{content_hash}/[...](content-addressed, immutable) - Ensure host URL builder parity: buildExtUiSrc() constructs correct src for Runner public base
- Document and enforce immutable cache headers at Runner; only static file types are served
- Do NOT implement a Next.js ext-ui route in ee/server; the Runner is the sole static UI host
- Manifest v2 validator/types
- Add manifest v2 schema: ee/server/src/lib/extensions/schemas/manifest-v2.schema.ts
- Fields:
name,publisher,version,runtime,capabilities[],ui.type='iframe'withentry,api.endpoints[](method/path/handler),precompiled,assets,sbom
- Fields:
- Wire v2 validation into registry install/publish flow (placeholder until Phase 1.4)
- Export validator/types from index: ee/server/src/lib/extensions/index.ts
- Minimal Registry v2 wiring to unblock Gateway
- Implement DB-backed methods in ExtensionRegistryServiceV2: ee/server/src/lib/extensions/registry-v2.ts
- createRegistryEntry, listRegistryEntries, getRegistryEntryByName
- addVersion (persist
runtime,api,ui,capabilities) - attachBundle (persist
content_hash,signature,precompiled)
- Add install resolution helpers (tenant → install → active version + content_hash)
- Signature shape validation stub; store signature (full verification in Phase 3)
- v2-first exports
- 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
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.tsgit 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
- Delete descriptor renderer and descriptors:
- Delete pages/tabs/navigation legacy UI:
- Delete security whitelist:
- Remove re-exports from:
B) Remove renderer, routers, server actions, hooks, dev/mock route
- Replace/remove legacy renderer:
- ee/server/src/lib/extensions/ui/ExtensionRenderer.tsx
- Migrate any callsites to iframe embed flow (using buildExtUiSrc() + bootstrapIframe())
- Delete legacy router:
- Delete server action for descriptor loads:
- Delete dev/mock hook:
- Delete dev/mock API route:
C) Remove MSP descriptor-based page and replace with iframe page (or remove)
- Delete or replace page:
- ee/server/src/app/msp/extensions/[extensionId]/[...path]/page.tsx
- If retained, render a sandboxed iframe using buildExtUiSrc() and bootstrapIframe()
D) Remove legacy schemas/validators/types
- Delete legacy manifest schema and extension points:
- Delete legacy validator helpers:
- Prune v1 UI component types from:
- ee/server/src/lib/extensions/types.ts
- Remove
ExtensionComponentTypeand Tab/Navigation/Dashboard/CustomPage types; keep only shared DB models still used
E) Delete prototypes/POCs
- Remove disregard prototype:
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/navigationgit rm ee/server/src/lib/extensions/ui/DescriptorRenderer.tsx ee/server/src/lib/extensions/security/propWhitelist.tsgit rm ee/server/src/lib/extensions/routing/ExtensionRouter.tsx ee/server/src/lib/actions/extension-actions/extensionActions.ts ee/server/src/hooks/useExtensions.tsgit rm ee/server/src/app/api/extensions/route.ts ee/server/src/app/msp/extensions/[extensionId]/[...path]/page.tsxgit 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.tsgit 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 -Agit commit -m "refactor(ext-v2): remove legacy descriptor-based UI, schemas, routes, and fallbacks"
Phase 3 — Finalize v2 enforcement and security
- Implement full signature verification on bundle publish/install:
- Trust bundle env (e.g.,
SIGNING_TRUST_BUNDLE) - Verify detached signature and
content_hashon install and load
- Trust bundle env (e.g.,
- Enforce capability grants on Runner invocation (gateway enforces)
- Enforce egress allowlists for http.fetch
- 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)
- Rewrite the following to present v2 as the only system:
- Remove status banners and any legacy descriptor references
- Update or remove example docs under 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
- Global search to ensure no references remain:
- Patterns:
"descriptors/pages/","DescriptorRenderer","TabExtensionSlot","NavigationRegistry","PageRegistry","loadExtensionDescriptor"
- Patterns:
- 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.tsee/server/src/lib/extensions/schemas/manifest.schema.tsee/server/src/lib/extensions/validator.ts
- 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:
- Manifest v2 validator accept/reject test matrix
- Gateway header allowlist/strip, path resolution, timeouts/errors
Integration (with mocked Runner /v1/execute):
- 200/404/413/502/504 response mappings and headers
- Correlation IDs propagated
- ext-ui route serves by
content_hashwith immutable caching and correct MIME types- URL parity with builder: ee/server/src/lib/extensions/ui/iframeBridge.ts
Build and typing:
tsccleannext buildpasses- 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
- 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}/...
- Remove any descriptor JSON assets from examples
- Reference SDKs where applicable:
@alga/extension-iframe-sdkand@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 gateway’s 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
- buildExtUiSrc(): ee/server/src/lib/extensions/ui/iframeBridge.ts
- bootstrapIframe(): ee/server/src/lib/extensions/ui/iframeBridge.ts
- ExtensionRegistryServiceV2: ee/server/src/lib/extensions/registry-v2.ts
- API Routing Spec Example: ee/docs/extension-system/api-routing-guide.md