Release an App
Version an App, declare host compatibility and deliver a reproducible package upgrade.
Release an App
Release Workshop as a Composer package, then adopt its version in a separate host change. This example publishes v1.2.3 with minimum Core 0.5.0 and SDK 0.5.0. Declare tested compatibility ranges and use a Composer repository your deployment can authenticate to.
Choose the version and compatibility ranges, test the candidate, publish its approved tag, then update the host requirement and committed lock. Finish with a clean packaged install and an existing-tenant upgrade.
Know which version you are changing
| Version | Declared by | Example and effect |
|---|---|---|
| App package | App Git tag | v1.2.3 releases this repository; Composer derives the version |
| SDK package | SDK release plus App require | ^0.5.0 permits compatible SDK patches; changing App code does not release the SDK |
| Core compatibility | App extra.nexia.core_version | ^0.5.0 declares supported Core patches; it does not install Core |
| Resource descriptor | ResourceDescriptor::version | '1.0' identifies a public Resource contract; independent of the App tag |
| Event payload | EventDraft::schemaVersion and catalog/subscription declarations | Positive integer such as 1; exact consumer compatibility is checked |
| Generated catalog format | Host generator | Resource-map schema 3 and Event-map schema 1 describe JSON layout, not your domain version |
Before 1.0, compatible fixes and additions increment the patch; breaking changes increment the minor. From 1.0, use patch for fixes, minor for compatible additions, and major for breaking changes. Core, SDK, and App versions are independent. Raise a dependency minimum only when the App needs a newer contract or host implementation.
Declare matching dependencies
The scaffold declares compatible Core and SDK ranges:
{
"require": { "amuzcorp/nexia-app-sdk-laravel": "^0.5.0" },
"extra": { "nexia": { "core_version": "^0.5.0" } }
}Keep the other metadata. Do not add a manual Composer version field; development branch aliases are not release tags. The compatibility command checks both declarations against installed versions. --core-version and --sdk-version simulate target versions; they do not install or test those releases.
Keep package.json's peerDependencies["@nexia/sdk"] at the same SDK range (^0.5.0). The frontend validator accepts exact versions or stable caret ranges. Core ^0.5.0 accepts 0.5.0 and later 0.5.x, excluding 0.6.0; SDK ^0.5.0 follows the same rule. Core 0.4.5 first supported frontend range validation; the current scaffold requires Core 0.5.0. Local SDK source is selected through the Core workspace flow; do not add a vendor or ad-hoc link: SDK dependency to an App manifest. Verify the supported minimum and candidate versions; metadata simulation is not a compatibility test.
A Core-only compatible patch keeps App and SDK tags. An SDK-only compatible patch keeps App tags; adopt the new SDK in the Core lock when needed. An App-only fix releases that App and changes the Core deployment lock. New SDK capabilities requiring a host implementation need both dependency minima on consuming Apps. See docs/project/GIT-WORKFLOW.md in the source repository for the release procedure.
Check the candidate
Finish Test an App, including migration and public-contract changes. From the Core root, with Composer loading the candidate:
task artisan -- nexia-apps:validate-app-compat --app=workshop --require-declarations
task artisan -- nexia-apps:validate-app-descriptors workshop
task artisan -- nexia-apps:validate-app-frontend-dependencies --app=workshop --require-manifests
task artisan -- nexia-runtime:generate-app-mapRecord the App commit and the installed Core/SDK versions with the results. The generated .github/workflows/ci.yml needs repository credentials and the intended Core test ref/version before manual dispatch. Its file alone proves no checks have run.
Publish the candidate and update the host lock
Complete the App work-branch PR/MR and release approval process. Create and publish the chosen tag on the accepted candidate in the App repository. For an approved v1.2.3 candidate, the explicit publication commands are:
nexia_release_commit=REPLACE_WITH_APPROVED_COMMIT_SHA
git show --no-patch --oneline "$nexia_release_commit"
git tag -a v1.2.3 "$nexia_release_commit" -m 'Release 1.2.3'
git push origin v1.2.3The host must declare the authenticated Composer repository serving that package and a requirement selecting the tag. A new unpublished Workshop package is not automatically available to production because local activation succeeded. Change the host's committed composer.json on a separate work branch, then from the Core root:
Merge this entry into the host’s existing require object, preserving the other dependencies and authenticated repository configuration. The exact constraint makes this first adoption unambiguous; widen it only as an intentional update policy.
{ "require": { "amuzcorp/nexia-workshop": "1.2.3" } }task apps:lock -- workshop
task apps:lock:verify -- workshopThese commands use committed composer.json/composer.lock, not ignored composer.local.*. Review the locked version and VCS reference. Publish a new SDK before an App that needs it; unchanged compatible Apps do not need new tags. Adopt the selected package set in Core last. Describe that order in related PR/MRs. Creating a PR is not merge approval.
Before a clean install or full release tests, check the committed lock against the target Core version:
task release:preflight CORE_VERSION=0.5.0This uses existing PHP/Composer tooling and checks metadata without fetching private packages. Existing exact-pinned tags require one new App release and lock adoption to transition to ranges; never rewrite a published tag or lock metadata.
Verify the packaged upgrade
Install the committed lock in a clean host environment without the local source overlay. Run the packaging gates above against that installation, then activate and inspect the target tenant plan. A clean install catches files hidden by a long-lived local mount.
For existing tenants, deployment runs tenants:migrate --force to update installed App schemas. New App installation runs its own pending migrations and initialization; already-active Apps may need their documented repair/upgrade procedure. A package tag alone does not migrate tenant databases, change user grants, or deploy the host.
Review saved descriptor selections and event consumers before removing or renaming public fields. Update compatible event declarations and consumers deliberately; never bump every version merely because the App tag changed. Regenerate catalogs for review, but edit the owning declarations rather than generated JSON.
Record App/SDK/Core commits, lock references, tested upgrade behavior and any required operator steps. App lifecycle explains activation, initialization and grants; Resource contracts defines descriptor compatibility surfaces.
Production catalog registration and tenant installation
Package delivery, catalog publication and tenant installation are separate steps. Once the production host loads the package, run:
php artisan nexia-apps:reconcile-app-catalog
php artisan nexia-apps:reconcile-app-catalog --checkA new App starts as private / draft. Choose its distribution audience and set it to published in Central App Catalog. For private Apps, grant the target tenant access to the App and its private prerequisites. Package readiness must be available or beta; development-only preview Apps cannot be installed through the production entry point.
nexia_tenant=REPLACE_WITH_TENANT_ID
php artisan tenants:run "nexia-apps:install-tenant-app workshop --dry-run" --tenants="$nexia_tenant"
php artisan tenants:run "nexia-apps:install-tenant-app workshop --with-prerequisites" --tenants="$nexia_tenant"Installation runs pending migrations in prerequisite order and initializes before activation. Assign user access separately. Later deployment runs of tenants:migrate --force update only Apps with installation history, including disabled Apps whose data remains intact. Existing tables for uninstalled Apps are not deleted. A migration failure preserves completed migration history; fix the cause and retry installation. New tenants do not load existing schema dumps that may contain all Apps. Pending tenants prepared by older releases retain their existing tables.