Module Registry
Module Registry
Section titled “Module Registry”KoAkademy distributes standalone modules through the public module registry. The registry contains two related indexes:
registry.jsonis the signed Marketplace catalog.packages.jsonis the Composer repository used during application builds.
The Marketplace is a catalog and module-status interface. It is not a live package installer. Composer and the application image remain the code delivery boundary.
If you are creating a new module from the beginning, follow the complete Create a Module guide. This page focuses on the registry, signing, installation, and update boundary.
How the pieces fit together
Section titled “How the pieces fit together”module repository and vX.Y.Z tag │ ├─ registry updater ──▶ signed registry.json + packages.json │ │ │ └─ GitHub Pages │ └─ KoAkademy composer.json/lock ──▶ application image ──▶ Swarm │ └─ Marketplace enable/disableUpdating the registry changes catalog information. It does not modify a
running container, install vendor/ dependencies, rebuild Vite assets, run
migrations, or restart Swarm.
The Marketplace fetches the signed catalog at runtime, using the configured cache TTL. Contributors can therefore publish new catalog entries without changing the KoAkademy core repository. A catalog entry describes an available release; it does not mean that the PHP package is installed in a particular image.
Install a standalone module
Section titled “Install a standalone module”From the KoAkademy application repository, configure the Composer registry and require the package:
composer config repositories.koakademy composer https://yukazakiri.github.io/koakademy-modulescomposer require koakademy/forms:^1.1Use this command after the package has a catalog entry in the public registry. The KoAkademy core repository may temporarily carry a direct package repository definition while a newly released module is waiting for its signed registry entry; that fallback is not a substitute for publishing the module to the catalog.
Commit composer.json and composer.lock, then build the normal KoAkademy
image. Run migrations in the release container when the package includes
database migrations, clear/rebuild application caches, and roll the Swarm
service. Only after the package is in the image should a super administrator
open Administrators → Marketplace and enable it. The enable/disable
decision is stored in module_installations, and the application shows a
restart-required notice until the workers have been rolled. At container
startup, modules:sync-statuses records installed package metadata without
overwriting existing administrator choices or clearing restart markers. After
every application replica has been updated and verified healthy, acknowledge
the completed rollout explicitly with
php artisan modules:sync-statuses --acknowledge-restart.
The current Forms package supports authenticated, guest-identifier, anonymous,
and record-bound invitation forms, protected submissions, reusable templates,
safe suggestions, and KoAkademy student-model mappings. Its built-in Student
Profile Completion template renders only missing fields and applies answers
with blank-only concurrency protection. Sparse fields use the host
students.profile_details JSON column while existing normalized columns remain
the first storage target.
When a newer catalog release is available, Marketplace shows an Update
button. For Composer-installed modules it displays and can copy the exact
composer require command for the release. For legacy source-tree modules it
explains that the source must be updated or migrated in the KoAkademy
repository. In both cases, updating still requires a new image build and a
rollout; the button never changes PHP code inside a running container.
See the Forms module repository
for its package-specific behavior and configuration.
Forms v1.1 operational checklist
Section titled “Forms v1.1 operational checklist”After installing or updating Forms:
- Run
php artisan migrate --forceso the template, invitation, field presentation, andstudents.profile_detailsmigrations are applied. - Confirm the package is installed in the image and the provider is visible
under
vendor/koakademy/forms. - Build the host frontend so the module’s Inertia pages and generated route helpers are included.
- Open Administrators → Marketplace and enable the installed module if the persistent status is disabled.
- Open Online Forms → Templates, choose Student Profile Completion, publish the generated form, then use Invitations to preview eligible students and explicitly queue email delivery.
Deployment and Marketplace refreshes never send invitations. Links are hashed at rest, expire after 30 days by default, are revoked on resend, and become unusable after completion. The queue must be running for delivery.
Publish or update a module
Section titled “Publish or update a module”Contributor steps
Section titled “Contributor steps”-
Keep the module source in its own repository.
-
Update
module.jsonandcomposer.json; keep the package name, provider, and repository identity stable. -
Create a matching public semver tag: manifest
1.2.3must use tagv1.2.3. -
In a checkout of the registry repository, download the exact tag archive:
Terminal window curl -L https://github.com/OWNER/REPOSITORY/archive/refs/tags/v1.2.3.zip \-o /tmp/module-v1.2.3.zipphp scripts/update-module.php \--module=/path/to/module-repository \--archive=/tmp/module-v1.2.3.zipphp scripts/validate-registry.php -
Open a pull request containing the generated
registry.jsonandpackages.jsonchanges, the module release/tag, compatibility requirements, migrations, permissions, and rollback notes.
The updater reads the module manifest and Composer metadata, calculates the SHA-256 and Composer distribution checksums, updates both indexes, sorts the entries, and removes the old signature. Contributors must not generate or commit a signing key.
Maintainer steps
Section titled “Maintainer steps”After reviewing the module and the generated diff, use the existing private registry key from protected storage:
php scripts/validate-registry.phpphp scripts/sign-registry.php registry.json /secure/registry-private.key registry.jsonphp scripts/validate-registry.phpphp scripts/verify-registry.phpMerge only after the signature verifies. Registry CI validates every change;
the Pages workflow validates the signed files again before publishing them.
Never generate a replacement key for an ordinary module update. Existing
applications trust the current public key, so key rotation requires a separate
migration of every MODULE_REGISTRY_PUBLIC_KEY secret.
The complete contributor checklist is in the registry repository’s
CONTRIBUTING.md.
Update a deployed module
Section titled “Update a deployed module”For a new Announcement release such as 1.0.2:
-
Release
v1.0.2from the Announcement module repository. -
Add the release to the signed registry and wait for Pages publication.
-
In KoAkademy, run:
Terminal window composer update koakademy/announcement --with-dependenciesphp artisan test --compactgit add composer.json composer.lockgit commit -m "chore(modules): update announcement"git pushIf Announcement is not yet a Composer dependency, use
composer require koakademy/announcement:^1.0.2instead. -
Build and deploy the new stable or edge image through the normal release process.
-
Run
php artisan migrate --forcewhen required, clear/rebuild caches, and roll every Swarm replica. -
Enable the installed version in Administrators → Marketplace if its persistent status is disabled, then roll the application workers when the Marketplace reports that a restart is required.
Existing deployments stay on the old module version until the application lockfile and image are updated. Marketplace refreshes do not perform these steps. The database state survives image replacement; the JSON status file is retained for first-boot defaults and compatibility with older releases.
Legacy source-tree modules
Section titled “Legacy source-tree modules”The six original modules under the application’s Modules/ directory are
source-tree modules and remain enabled by the image’s status file for backward
compatibility. A standalone repository with the same module name does not
automatically replace that local source.
Migrate a local module to its Composer package as a separate, tested change.
Keep the existing module enabled during the migration unless the migration
plan explicitly changes its status. The module_installations row preserves
administrator choices across application upgrades.
Configuration and troubleshooting
Section titled “Configuration and troubleshooting”The current installer and Swarm templates default to:
MODULE_MARKETPLACE_ENABLED=trueMODULE_REGISTRY_REQUIRE_SIGNATURE=trueMODULE_REGISTRY_URL=https://yukazakiri.github.io/koakademy-modules/registry.jsonMODULE_SCAN_VENDOR=trueMODULE_ACTIVATOR=databaseThe registry public key must match the catalog trust root. If Marketplace shows a module but cannot enable it, confirm that the matching package is installed in the image, its provider is discoverable, its compatibility check passes, and its dependencies are enabled. If the signed catalog cannot be reached, installed modules remain visible but remote catalog information may be unavailable.
Core-only installations
Section titled “Core-only installations”A core-only image should omit optional Composer packages. It can still display the signed Marketplace catalog, but catalog entries are shown as Not installed and cannot be enabled until the package is added to the application dependency manifest and a new image is built. An official full distribution can ship the same packages in its image while initializing optional modules as disabled for new installations.