Skip to content
Reference

SDK contracts

Find public PHP capabilities by namespace and distinguish host calls, App contributions, and direct-use values.

SDK contracts

Choose the namespace for your task below. Consume means inject a host capability; implement means publish an App contribution; construct means use a value, helper, or adapter directly. A namespace can contain more than one kind.

Use a host capability

Code example
PHP
use Nexia\Tenancy\Contracts\TenantSettings;

final class ReportClock
{
    public function __construct(private TenantSettings $settings) {}

    public function timezone(): string
    {
        return $this->settings->businessTimezone();
    }
}

Resolve ReportClock through Laravel in a restored tenant context. It returns that tenant's business timezone through the host binding. For Resource authorization, start with Resource contracts; for frontend imports, use React components and hooks.

PHP namespace map

NamespaceHow the App uses itContents
Nexia\AppRuntimeconstruct / implementAbstractPackageAppManifest, AppDefinition, AppPackageMetadataReader, manifest contracts
Nexia\Contributionimplement / constructResourceCatalogContribution, InheritedSearchVisibilityContribution, ResourceAuthorizationContract, ResourceRecordOwner
Nexia\AppDescriptorsimplement / construct / consumeDescriptor contributions, public lifecycle-event schemas, and strict contribution validation
Nexia\Agentconstruct / implementApp-owned route-backed Agent tool declarations and app-neutral routing, effect, surface, lane, executor, and tier values
Nexia\Permissionconstruct / implementAssignmentScope, PermissionContribution, PermissionDefinition, RolePresetContribution, LegalEntityMemberSelfAccessContribution, PresetType, GrantControl, SubjectPopulation
Nexia\AccessconstructApp-neutral AuthorizationContext and RoleCatalog values
Nexia\Laravel\Accessconsume / reuseLaravel host contracts ResourceAuthorization, PermissionAuthorizer, SubjectPermissionAuthorizer, TenantPermissionSnapshotAuthorizer, and the EvaluatesPermissionDecision concern
Nexia\Laravel\IdentityconsumeHost Party lookup and query composition without exposing the Core Party model
Nexia\Laravel\Modelsextend / reuseLaravel adapter bases and model concerns, plus the host-configured Scout identity and engine resolver registry; the app-neutral kernel has no model base namespace
Nexia\Laravel\Filtersconstruct / implementLaravel adapter filters and sorts: Exact, Callback, HasRelation, Column, RelationSort, and the Filter / Sort contracts
Nexia\Laravel\ResourcesconstructResourceListFields, the unified search/filter/sort catalog consumed by Filterable
Nexia\Laravel\ResourceReferenceconsume / constructHost availability contract and paginator-to-ResourceReferencePage adapter
Nexia\Navigationimplement / constructNavigationContribution, NavigationItem, ShellNavigationLocateAction, destination concerns
Nexia\Paletteimplement / constructPaletteCommandContribution, PaletteCommand, and executable-command helpers
Nexia\Dashboardimplement / constructDashboardWidget, DashboardWidgetKind, DashboardWidgetParameter, RendererCapability, query sources
Nexia\Approvalconsume / constructApproval read models, frozen binding submissions, and host contracts
Nexia\Processconsume / implement / constructBPMN types, status enums, ProcessRuntime, instance snapshots, namespaced durable message delivery and receive-task correlation
Nexia\Identityconsume / constructActor, Party directories, person-Party provisioning, actor-filtered Party access and relationship projections, and optional batch profile and invitation lookup capabilities
Nexia\SecurityconsumeHost-owned recent-authentication proof for protected App actions
Nexia\DocumentsconsumeHost-bundled local PDF font assets and their provider contract
Nexia\Organizationconsume / constructLegalEntity, OperatingUnit, OrganizationDirectory, OrganizationMemberships
Nexia\TenancyconsumeTenantIdentity, TenantRunner, TenantSettings
Nexia\Eventsconsume / implement / constructEventEnvelope, ConsumerResult, EventConsumerRegistration, subscription and recovery modes, EventPublisher, EventDraft, Outbox, InboxConsumer, and App listener contracts
Nexia\ResourceReferenceconsume / implement / constructResourceRef, safe and protected ResolvedResourceReference values, single and batch resolution, declared-field selection, paged search, effective-range search, Party selection constraints, and availability
Nexia\ResourceCompositionconstruct / implementStrict CompositionSpec and the App-owned authorized-query provider contribution
Nexia\Laravel\ResourceCompositionconstructAuthorizedCompositionQuery and CompositionQueryContext carry the restored Laravel query, actor and request
Nexia\ResourceTransferimplement / constructTransfer schemas, reference columns, and export source contributions
Nexia\ResourceImportconsume / implement / constructApp-owned recipe and pipeline contributions, repeatable and temporarily spooled analysis rows, chunked validation, typed decisions, analysis snapshots, queued execution and safe-workbook host contracts, intrinsic definition validation, server-owned DataMigrationStageIdentity, normalized batch state, stages, fill proposals, and disposition totals
Nexia\Attachmentsconsume / constructStores, authorized readers, directories, targets, safe file/attachment projections, and authorized import-file claims with temporary-copy callbacks
Nexia\AsyncWorkconsume / constructActor-owned transient operation status, progress, and results plus atomic identity-bound apply reservations
Nexia\DataMigrationconsume / constructStable execution identity, lifecycle status, safe result metadata, and the host recorder contract for durable migration evidence
Nexia\Templatesimplement / constructCopyableTemplateContribution, application context, source and result value objects
Nexia\Setupimplement / constructApp-neutral Setup task contribution and evaluator contracts, immutable declaration and assessment DTOs, completion mode, and importance
Nexia\Mutationconsume / constructMutationMatcher, lifecycle/action MutationOperation values, and the explicit MutationPublisher host capability
Nexia\Testingconsume (tests)Test-only host setup contracts and opaque host-record projections
Nexia\Httpuse constantsMiddleware aliases
Nexia\Laravel\Httpextend / reuseControllers\Controller, organization-target request and list-query helpers
Nexia\Laravel\HttpconstructLaravel list-query adapter for App controllers
Nexia\AuditconstructAuditEntry
Nexia\Signatureconsume / implement / constructConsume SignatureHost and document capabilities; implement data-source/bulk providers; construct request values. Electronic Signature contracts
Nexia\OfficialSealconsumeConsume OfficialSealDirectory and OfficialSealUseService; receive seal summaries and assets
Nexia\Fixtureimplement / constructImplement FixtureContribution; construct fixture keys, references, and context
Nexia\Guidanceimplement / constructImplement FeatureGuideContribution; construct guide definitions and steps
Nexia\ResourcesconstructConstruct ResourceListQuery, ResourceListQuerySchema, and ResourceListSort values
Nexia\SelfServiceconsume / implement / constructImplement action-item and work-context contributions; consume SelfWorkContextRefs
Nexia\Supportcall helperCall CanonicalPayloadFingerprint for deterministic payload identity

Output or return: Interfaces versus implementations

Where the platform owns the behavior, the SDK publishes an interface and the platform binds the implementation. It does ship app-neutral implementations of its own — the Nexia\Laravel\Models adapter, its model concerns, and the frontend primitives and hooks — so "contracts only" is true of platform behavior, not of the whole package. The pattern for platform-owned behavior:

You depend onThe platform provides
Nexia\Laravel\Access\Contracts\ResourceAuthorizationResource row-visibility and action authorization
Nexia\Laravel\Access\Contracts\TenantPermissionSnapshotAuthorizerA fail-closed tenant permission snapshot for read-only UI affordances
Nexia\Identity\Contracts\ActorDirectoryActor resolution
Nexia\Identity\Contracts\PartyAccessParty-backed row visibility
Nexia\Identity\Contracts\PartyRelationshipDirectoryActor-filtered Party relationship lookup
Nexia\Identity\Contracts\PersonPartyProvisionerEnsure a person Party for an App-owned directory subject from display name and optional email
Nexia\Identity\Contracts\BatchPersonProfileDirectory / BatchPersonLoginInvitationsOptional bulk profile and login-invitation lookup without per-person host calls
Nexia\Laravel\Identity\Contracts\PartyDirectoryParty lookup and active-person option search without exposing the Core model
Nexia\Identity\Contracts\BatchPartyDirectoryOptional bulk active-person lookup by email without exposing the Core model
Nexia\ResourceReference\Contracts\ReferenceAvailabilityOwner lifecycle and type-level authorization state; an optional context must match the supplied actor and Legal Entity
Nexia\Security\Contracts\RecentAuthenticationA recent-authentication proof for a protected action; it does not replace permission or record authorization
Nexia\Documents\Contracts\PdfFontProviderA locale-matched host-bundled local font without exposing Core path construction to the App
Nexia\Organization\Contracts\OrganizationDirectoryLegal Entity and Operating Unit lookup
Nexia\Tenancy\Contracts\TenantRunnerRestore one trusted tenant around a callback (runFor, false when absent) or iterate every tenant (runForAll); neither restores an actor
Nexia\ResourceReference\Contracts\ResourceReferencesCore-governed exact, batch, paged, and effective-range dispatch to owner-authorized providers
Nexia\ResourceReference\Contracts\ResourceReferenceSelectionsCore enforcement for one descriptor-declared browser or write-time selector field, returning availability with an exact result or page
Nexia\Events\Contracts\EventPublisherPublish a declared public Event inside the App transaction
Nexia\Events\Contracts\AppEventListeners / ActorDelegatedAppEventListenersTenant-gated App listener registration with explicit subscription and recovery metadata; delegated listeners also restore and reauthorize an actor
Nexia\Mutation\Contracts\MutationPublisherAfter-commit browser wake-up hints for bulk/non-observed Resource changes and successful semantic actions
Nexia\Attachments\Contracts\AttachmentDirectorylistForTargets() lists authorized attachment summaries for Resource targets
Nexia\Attachments\Contracts\AuthorizedFileReaderread(filePublicId, legalEntityKey, actor) reads an authorized, isolated, clean file; refusal and absence both return null
Nexia\Attachments\Contracts\AttachmentStoreStore generated files, attach to Resources, check duplicates and obtain authorized download URLs
Nexia\Attachments\Contracts\FileLifecycleRecorderRecord bounded file identity and lifecycle metadata after authorization; exclude contents and credentials.
Nexia\Attachments\Contracts\FileDeliveryAttemptsPersist a delivery attempt before sending bytes and record observed server outcomes; browser receipt is not inferred.
Nexia\Attachments\Contracts\AuthorizedImportFileReaderClaim an import-only uploadIntentPublicId in Resource/Legal Entity/actor context and read authorized bytes
Nexia\Attachments\Contracts\AuthorizedImportFileStoreActor-, Legal Entity-, and Resource-bound import-file claims plus checksum-verified temporary local copies
Nexia\AsyncWork\Contracts\BackgroundOperationStoreActor-owned transient operation tickets and bounded progress/results plus an atomic apply reservation that distinguishes an identical retry from conflicting work
Nexia\ResourceImport\Analysis\Contracts\ImportAnalysisStoreResource/scope/actor-authorized access to short-lived encrypted parser results cached by Media checksum, analysis kind, and parser version
Nexia\ResourceImport\Execution\Contracts\QueuedImportExecutionRestored tenant, actor, organization scope, and request context in which queued import work performs its point-in-time authorization checks
Nexia\ResourceImport\Workbook\Contracts\SafeWorkbookInspectorHost archive/XML safety inspection before an App parser opens an untrusted workbook
Nexia\DataMigration\Contracts\DataMigrationRunRecorderDurable server-owned start, clean completion, partial completion, and failure evidence without exposing the host model
Nexia\Process\Contracts\ProcessRuntimeEvent-start availability, read-only instance lookup, and durable exact activity correlation with ProcessMessageDelivery / ProcessMessageIdentity
Nexia\AppDescriptors\Contracts\ResourceSummariesResource summary provider discovery and dispatch
Nexia\Testing\Contracts\*Test-environment fixture and inspection surfaces without host models

Resolve directly bound host contracts from the container. The optional batch contracts above have no separate binding: inject Nexia\Identity\Contracts\PersonProfileDirectory, Nexia\Identity\Contracts\PersonLoginInvitations or Nexia\Laravel\Identity\Contracts\PartyDirectory, then check that the returned implementation implements its corresponding batch interface. Current Core implementations support all three batch capabilities. Never type-hint a platform class or use its Eloquent model as an App API.

Nexia\Tenancy\Contracts\TenantIdentity, Nexia\Identity\Contracts\Actor and Nexia\Identity\Contracts\Party are identities supplied through context or call results, not services to assume independently injectable. Contributions and App providers are implemented by the App; test-host bindings are configured only in the test environment.

The batch profile and Party directories query only the tenant context already restored by the caller; their keys and emails are not cross-tenant selectors. Batch login-invitation status additionally requires the current Actor and a Legal Entity key, and reports NotAuthorized when that actor may not invite.

PersonPartyProvisioner::ensureForDirectorySubject($displayName, $email) returns the app-neutral Party contract. The host reuses the single unambiguous active person Party for the email, including one already linked to a user; otherwise it creates a person Party. The App receives no host model and must not reimplement email-based identity convergence itself.

RecentAuthentication::isFresh($actor, $withinMinutes) is an additional proof for a protected action. Keep the operation's permission, row, scope, and state checks in place. PdfFontProvider::forLocale() returns a host-owned local PdfFontAsset when an App needs to embed a font in a generated PDF; the App must not reconstruct Core filesystem paths.

PartyDirectory::searchActivePeople($search, $limit, $excludedKeys) returns PersonDirectoryEntry options with an opaque key, public id, display label, and optional contact email.

ResolvedResourceReference keeps public fields separate from protectedValues(). Protected values are accepted only from an exact resolve() or resolveMany() call whose context explicitly sets includeProtectedValues; searches reject them, and snapshots, debug output, and PHP serialization omit them. People uses this boundary to return bank account values for the exact payroll.bank-export purpose without making a People-specific payment contract part of the SDK. The same owner can add a safe effective planned-schedule projection for the workforce.effective-planned-schedule purpose, bounded by asOf and effectiveThrough. Actorless consumers use a public Event and local projection instead of fabricating an actor.

Tenant permission snapshots

TenantPermissionSnapshotAuthorizer evaluates several tenant-scoped permission keys with one app-neutral contract:

Here $user is the authenticated host user already supplied to the request. These two tenant-scoped Core permissions demonstrate the shape; pass the tenant-scoped permissions needed by your UI.

Code example
PHP
use Nexia\Laravel\Access\Contracts\TenantPermissionSnapshotAuthorizer;

$snapshot = app(TenantPermissionSnapshotAuthorizer::class)->forPermissions($user, [
    'system.apps.read',
    'system.data.export',
]);

The result contains every requested string key verbatim. Unknown or retired permissions, permissions from a non-operational App, non-tenant permissions, and subjects that cannot be resolved all evaluate to false; non-string input is ignored. The contract uses the ambient tenant and deliberately accepts no Legal Entity or Operating Unit argument. Use the snapshot to render read-only affordances such as menus or buttons. A write still performs point-in-time authorization in its request path.

AttachmentDirectory::listForTargets() accepts AttachmentTarget values and returns attachment summaries visible to the actor; it does not read bytes. AuthorizedFileReader::read() takes a filePublicId. In the restored tenant and request Legal Entity context, it checks actor authorization, isolation and clean status; absence, refusal, boundary mismatch and an unclean file return null.

AttachmentStore::createGeneratedFile() stores a generated file and attach() links it to a Resource target. exists() checks an attachment public id against the target; fileAttached() checks whether a file public id is already linked. These checks are not uniqueness constraints or domain mutation authorization. The App must authorize its business write and handle duplicates before storing/attaching. downloadHrefIfAuthorized() returns a URL only when the actor may read it.

For import-only uploads, AuthorizedImportFileReader::read(uploadIntentPublicId, resourceKey, legalEntityKey, actor) claims and reads the upload. Use AuthorizedImportFileStore::claim(), find() and withLocalCopy() for metadata reauthorization or temporary-copy processing of larger files. Neither contract is the general Resource attachment directory.

Party relationship and Resource Summary lookups likewise return no projection when the actor-visible provider cannot answer; callers do not receive a host model or a reason that widens disclosure.

There is no kernel Nexia\Models namespace or host-model facade. Use the focused Identity, Organization, Party, or Installed Apps contract; production Apps never query or receive a host Eloquent model. Nexia\Testing\Contracts\HostTestStore is test-only.

Mutation identity and publication

MutationMatcher is an app-neutral recheck condition. It names either Resource Catalog keys with lifecycle operations (Created, Updated, Deleted, Restored) or semantic action keys with only Succeeded. It cannot mix the two subject types. Keys and operations inside one matcher use OR semantics; optional resourceIds narrow a Resource matcher. Resource keys, action keys, and Resource IDs are each limited to 160 UTF-8 bytes across the SDK, host header, Gateway, and Shell boundaries.

The host automatically observes committed Eloquent lifecycle events for every model bound through ResourceCatalogContribution. Ordinary generated Resource controllers therefore add no save/delete instrumentation. Inject MutationPublisher only when the write bypasses model events, such as a bulk query update, or when a successful semantic action has no Resource Catalog root:

Code example
PHP
use Nexia\Mutation\Contracts\MutationPublisher;
use Nexia\Mutation\MutationOperation;

$mutations = app(MutationPublisher::class);
$mutations->resourceChanged(
    'workshop.note',
    MutationOperation::Updated,
    $publicId,
);

$mutations->actionSucceeded('workshop.note.archived');

Call the publisher only after the business write succeeds. The host derives tenant, actor, initiator, request, surface, and correlation context from its trusted runtime; App code supplies none of them. Publication occurs after the current transaction commits, or immediately when no transaction is active.

This signal is a same-browser wake-up hint, not a durable domain event, audit record, cache invalidation, or completion result. A consumer always re-reads authoritative state. Use Nexia\Events when another App or runtime must react reliably.

Cross-App access

App-to-App imports and package dependencies are forbidden. There is no exception. Three supported alternatives:

NeedMechanism
Read another App's recordNexia\ResourceReference — resolution and search contributions
React to another App's changeNexia\Events — consume a cataloged public Event through an explicit replay, reconcile, or ephemeral recovery contract; only delegated listeners restore the user and recheck authority
Share a capabilityPublish an app-neutral SDK contract and bind it in the platform

A ResourceRef names another App's record without importing its model. Core resolves it, applies the actor's authority, and returns only what they may see. The canonical browser selector also requires the consuming Resource and field, then enforces its declared targets, purpose, permissions, and owner availability before dispatch.

For a manually built Dashboard that reads across two Resources, Core composes the existing Resource contracts instead of asking either App to import the other. The SDK publishes only the app-neutral CompositionSpec wire DTO and matching PHP/TypeScript validators. The spec names semantic Resource keys, source aliases, a server-issued relationship key, fields, bounded filters, dimensions, measures, and result shape. It has no table, model, SQL, arbitrary expression, planner, or executor surface. Core resolves the keys against the live actor-filtered catalog and repeats authorization when it plans and runs the query. This is a manual human Dashboard capability, not an App or Agent authoring interface.

When a surface is missing

Check the installed package and host version before adding an API. A source checkout is only needed when you are changing that package. Keep App-specific behavior local and use Resource contracts or published events for cross-App integration. Request a platform capability when the existing public APIs cannot express the task; consume it once both SDK and host support it.

Do not import Core classes, another App, or edit vendor/. To add an available SDK checkout to an existing local setup, use task apps:add PACKAGES=app-sdk.

Capabilities without an App-side contract today

CapabilityHost-only class
Site ConfigurationApp\Settings\SiteConfigRegistry
Installation initializersApp\AppRuntime\TenantAppInitializerContribution

Neither class is an SDK API. Consider Site Configuration as a separate SDK candidate only after an actual App needs to contribute declarative items to the shared settings screen. For an App-owned settings screen, follow Add a settings page. First evaluate installation needs against tenant migrations and Required installation content, optional Copyable templates, and Contribute Setup tasks for operator readiness.

Existing package imports of host-only surfaces, when any remain, appear as explicit exceptions in .nexia/coupling-baseline.json. A clean App has no file; the ratchet permits only recorded file-and-symbol pairs and rejects new ones.

Errors

MessageCauseResolution
Coupling ratchet rejects a new file-and-symbol pairA new App\* reference from a packageImport from Nexia\*, check the installed SDK capability
Class "Nexia\..." not foundThe installed SDK does not export the symbolCheck the namespace and installed package version; use a compatible SDK and host release
Target [Nexia\...\Contracts\X] is not instantiable.The platform has no binding for that contractThe contract exists but is unbound — the host binding is missing
Module not found: @/... or @shell/... in a packageFrontend platform alias importImport from @nexia/sdk

Use in your App

Use the installed SDK namespace and the host binding together. For a first Resource, follow Create a Resource; the generated files show the model, authorization, and contribution APIs in context.

Use FileDeliveryAttempts::callback(attemptId, producer) around the actual byte producer after prepare(). It records server start and terminal outcomes; a constructed response does not establish delivery. FileLifecycleRecorder accepts bounded identity/context metadata only and does not grant authorization. Inventory observations and retention-pending facts do not claim historical downloads or deleted bytes.

AuthorizedImportFileStore::receiveLocal() routes existing multipart input through verified host intake. discardUnbound() is for a newly claimed input that your App has not bound to a business record (for example, a rejected duplicate upload); do not pass accepted evidence. Custom implementations must provide both methods and delivery callbacks when adopting this SDK change.

Source of truth: docs/developers/content/en/app-sdk/sdk-contracts.md