Skip to content
Concept

App lifecycle

The five stages between a package existing and an App serving requests, and what each one does and does not grant.

Runtime and installation lifecycle

When an App does not appear, identify the missing stage below before changing its code. A source checkout, Composer installation, tenant operational state, and actor access are separate facts. Follow Create an App Package for the first setup; use this page to diagnose activation, initialization, and grants.

What it is

An App present in Composer is not an App a user can use. Five stages sit between them, and each is a separate operation with a separate failure mode:

Check each stage independently; a source or installation problem can look like a navigation problem.

StageCommandScopeGrants access
Package source—FilesystemNo
Host activationnexia-apps:activate-package-appWhole hostNo
Tenant installationnexia-apps:install-tenant-appOne tenantNo
Initializationpart of installationOne tenantNo
Access Grantan administrator, in the UIOne actorYes

The last stage is often called "assigning a role", which is the UI shorthand. The record that carries authority is an Access Grant: it binds an actor, one or more Roles, a Data scope, a Subject population, and a validity period. AccessGrant documents itself as the sole durable source of standing action authority — Role membership alone grants nothing.

How it fits: Stage by stage

Host activation

Code example
Shell
task artisan -- nexia-apps:activate-package-app workshop

Validates every package definition's prerequisite graph, installs the package into the host's Composer requirements, then synchronizes Permission definitions and Core Role definitions.

PropertyBehavior
Prerequisite problemsMissing prerequisites, duplicate keys, or cycles stop activation before any host change
DatabaseManifest sync is strict — an unreachable database fails the command
FrontendWithout --build-assets, a running Vite process needs a restart
GrantsPermission definitions only. No authority

Tenant installation

For local development (APP_ENV=local), set nexia_tenant to one ID from tenants:list. This command leaves publication and readiness unchanged. Production uses nexia-apps:install-tenant-app after catalog publication and any private tenant entitlement; follow Release an App.

Code example
Shell
task artisan -- nexia-apps:install-dev-app workshop --tenant="$nexia_tenant" --dry-run
task artisan -- nexia-apps:install-dev-app workshop --tenant="$nexia_tenant" --with-prerequisites

Writes a row per App into tenant_app_installations with an operational status and an initialization state:

StateMeaning
pendingRow written, initializers not complete
initializedInitializers completed
failedAn initializer failed; the error is recorded on the row

The order is fixed: validate the prerequisite closure → apply its pending migrations in prerequisite order → write pending rows → synchronize the tenant's permissions and baseline Roles → run each App's initializers in separate transactions → mark the plan initialized.

Separate transactions mean an initializer that already committed is not rolled back. The sequence still stops at the failure, and every item left pending in that plan is marked failed alongside it. nexia-apps:repair-tenant-app replays the normal installation plan, including pending migrations. For unpublished local Apps, rerun nexia-apps:install-dev-app instead.

Operational

An App is exposed only when its installation is active, its initialization is complete, and every prerequisite is also operational.

The app.installed:{app_key} middleware refuses requests while an App is pending or failed. Its PHP routes may remain registered, but tenant consumers cannot use its protected routes, navigation, descriptors, or widgets.

Code-owned versus persisted

Product declarations remain code-owned, but contribution discovery has its own persisted build artifact:

Persisted product stateGenerated or code-owned runtime surface
Permission definitionsContribution interface-to-class manifest
Core Role definitionsNavigation items and descriptors read through that manifest
tenant_app_installations rowsPage elements and routes derived from indexed classes
Rows created by initializersLocale catalogs
Copies created by templatesInstalled App map and public Resource descriptor map

Rebuild both generated maps after changing contribution source:

Code example
Shell
task artisan -- nexia-runtime:generate-app-map
task artisan -- nexia-runtime:refresh-runtime-caches
task artisan -- nexia-apps:activate-package-app workshop --build-assets

Then restart long-running processes — queue workers, Octane, Horizon, and Vite. A process holding an autoloader from before your class existed cannot see it.

Boundaries

No availability stage grants authority. Activation, installation, and initialization make declarations available. Protected destinations and operations still require the actor's applicable permissions.

Deactivation is ordered. nexia-apps:deactivate-tenant-app is refused while dependent Apps remain active.

Prerequisites constrain lifecycle only. prerequisite_apps affects install and activation order. It grants no access to the prerequisite App's data.

Repair, do not hand-edit. A failed installation is recovered with nexia-apps:repair-tenant-app, which replays the plan. Editing installation rows directly leaves the state inconsistent with what initializers actually did.

Use in your App

A folder under packages/ proves only that source exists. Confirm Composer resolves the package and the generated App map contains it before diagnosing tenant installation. After installation, inspect initialization and prerequisite state. Finally check the exact permission required by the destination; a permission-free overview and a protected Resource route need not have the same visibility.

New tenants receive Core schema only. Later tenants:migrate runs include Apps with installation history, including disabled Apps; deactivation retains their tables and data. For an unpublished local App, use nexia-apps:install-dev-app <app-key> --tenant=<tenant ID> --with-prerequisites for installation or recovery. Normal installation and repair continue to enforce distribution policy.

Source of truth: docs/developers/content/en/core-runtime/runtime-lifecycle.md