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

115 lines
4.6 KiB
Markdown

# PRD — Extension SDK Client And Service Read Capabilities
- Slug: `extension-sdk-client-service-read-capabilities`
- Date: `2026-03-26`
- Status: Draft
## Summary
Add read-only extension host capabilities for tenant-scoped client and service catalog lookup so extension handlers can read those records without making HTTP API calls.
## Problem
Handlers that need client lists or service catalog data currently have to rely on API-like transport patterns. That creates unnecessary coupling to routes and credentials and makes scheduled or webhook-driven extension execution awkward.
## Goals
- Add first-class host capabilities for reading clients and services from extension handlers.
- Support both user-backed and non-user execution contexts.
- Keep the extension contract typed, small, and versionable.
- Reuse existing internal query logic instead of duplicating API controllers.
- Enforce capability grants, RBAC behavior, and tenant isolation in one place.
## Non-goals
- Mutating clients or services.
- Exposing arbitrary database queries.
- Returning the full internal `IClient` or `IService` shapes.
- Replacing existing HTTP APIs for the web app.
## Users and Primary Flows
- Extension authors building tenant automations that need lookup data.
- Scheduler-driven handlers that need to read clients or services without a user session.
- Webhook-style handlers that need service catalog context during execution.
Primary flows:
- Extension lists clients with simple pagination and search.
- Extension fetches one client by id.
- Extension lists service catalog entries with simple filters.
- Extension fetches one service by id.
## UX / UI Notes
This work is backend and SDK facing. The main user-facing ergonomics are:
- extension authors import typed host bindings
- handlers avoid HTTP fetches to Alga
- capability names remain explicit in manifests
## Requirements
### Functional Requirements
- Introduce `cap:client.read` and `cap:service.read`.
- Add `clients.list`, `clients.get`, `services.list`, and `services.get` host operations.
- Return summary-shaped records rather than full internal entities.
- Support pagination and a minimal filter set for list operations.
- Enforce normal `client:read` and `service:read` permissions when a user is present.
- Allow capability-only tenant-scoped access for non-user contexts.
- Return nullable results for not-found `get` operations.
### Non-functional Requirements
- No handler-side HTTP dependency for these reads.
- Stable WIT and TypeScript surface for SDK consumers.
- Clear error semantics for not-allowed, invalid-input, and internal failures.
- Provider behavior must be unit testable without UI or HTTP routing.
## Data / API / Integrations
- Extend extension runner WIT with `clients` and `services` interfaces.
- Extend `sdk/extension-runtime` host bindings and mocks.
- Add runner capability providers for both interfaces.
- Extract or factor shared read services from the current client and service action layers.
Likely internal reuse points:
- `packages/clients/src/actions/clientActions.ts`
- `packages/billing/src/actions/serviceActions.ts`
## Security / Permissions
- Install capability grant is mandatory.
- User-backed executions must also pass the existing RBAC checks.
- Non-user executions may read tenant-scoped data when the install capability is granted.
- Extensions cannot override tenant id in capability input.
## Observability
- Provider calls should emit structured runner logs for capability name, tenant, extension, result count, and error type.
- Failures should distinguish capability denial, RBAC denial, invalid input, and internal query failure.
## Rollout / Migration
- Add the new capabilities behind normal manifest capability declarations.
- Ship a sample extension that exercises the new host APIs.
- Keep existing HTTP-based patterns working; this is additive.
## Open Questions
- Include tags in client summaries in v1 or defer.
- Include currency-specific prices in service summaries in v1 or defer.
- Decide whether future write support should be separate capabilities.
## Acceptance Criteria (Definition of Done)
- Extensions can read clients through a typed host capability without HTTP.
- Extensions can read services through a typed host capability without HTTP.
- User-backed execution respects existing `client:read` and `service:read` permissions.
- Non-user execution works when the install capability is granted.
- The SDK exposes typed bindings and mock bindings for both capabilities.
- Runner/provider tests cover user, non-user, denial, invalid input, not-found, and tenant isolation cases.
- A sample extension demonstrates end-to-end usage.