Repository navigation
Administrator Upgrades and Rollback
Treat every Stream Engine upgrade as a controlled change to application code, dependencies, database schema, persistent files, and caches. A successful upgrade is one that can also be reversed within the agreed rollback window.
Stream Engine currently has no in-application updater, maintenance mode, or automatic database downgrade. Administrators must deploy a verified release, run its forward migrations once, test it, and retain a complete recovery path.
Important
Do not use a rolling or zero-downtime deployment unless the release notes explicitly declare the old and new releases compatible with the same database schema. The current general procedure uses a maintenance window and permits only one application release and one scheduler to write at a time.
Use a tagged release from the project's GitHub Releases page or the corresponding Composer package version. Do not deploy an arbitrary branch, unpinned dependency resolution, or a moving container tag to production. Maintainers prepare and verify those versions using the Developer release process.
Before scheduling the change:
- record the currently deployed version, artifact checksum or immutable commit, PHP version, database server and version, and deployment configuration revision;
- read the release notes and changelog for every version between the current and target releases;
- follow any required intermediate upgrade, data conversion, or manual step;
- confirm the target release's PHP extensions, database, Memcached, and web server requirements;
- check custom themes, site-owned files, and integrations against the target release;
- review new environment variables and changed defaults without replacing existing secrets; and
- identify the exact old artifact and dependencies needed for rollback.
Do not infer compatibility only from a matching major or minor version. Stream Engine is under active development, and a release note can impose a narrower upgrade path.
Existing sites are upgraded with migration files supplied by the target release. From an application root, these commands inspect and apply them:
composer migrate:status
composer migratecomposer migrate:status is read-only. It compares available migration files
with storage/migrations.json; it does not prove that the database contents
are healthy. composer migrate connects using .env, takes a filesystem lock
at storage/migrations.json.lock, executes pending SQL files in filename
order, and records each completed file in storage/migrations.json.
Do not run the installer, import resources/install/schema.sql, or baseline
migrations during an upgrade. Those operations are for a new installation or
a release-building workflow, not for advancing a working site.
storage/installation.json records the completed installation workflow; its
embedded release is not the deployed-version marker. Preserve the file and do
not edit it to announce the target release.
Warning
There are no down migrations. Statements inside a migration file are
executed sequentially, and the file is recorded only after all its
statements finish. If a statement fails, the database may be partly changed
even though that migration is not recorded as applied. Stop the deployment
and restore the pre-upgrade recovery set. Do not edit
storage/migrations.json or rerun the migration blindly.
The migration lock prevents two migration commands sharing the same state file from running concurrently. It does not make SQL transactional, stop web requests, coordinate a second release directory, or replace an external maintenance window.
Restore a recent production recovery set into an isolated environment as described in Backups and restore. Use isolated database credentials, upload paths, cache namespace, email sink, canonical URL, and scheduler configuration.
In that environment:
- deploy the exact target artifact with production-equivalent PHP and database server versions;
- run
composer check-platform-reqs --no-dev; - run
composer migrate:statusand record the expected pending files; - run
composer migrateonce and record its duration and output; - run
composer migrate:statusagain and requirePending: 0; - complete the smoke tests in this chapter;
- exercise important custom themes, routes, uploads, mail, and scheduled work;
- measure the maintenance time required for backup, migration, and checks; and
- rehearse the rollback with the old artifact and the pre-upgrade recovery set.
A test against an empty database is useful but does not replace a rehearsal against a sanitized copy of the site's real state.
Assign an operator and a rollback decision maker. Define:
- the maintenance start and expected finish;
- the last time at which rollback may be chosen;
- the maximum acceptable data loss and service interruption;
- the exact health checks that permit reopening traffic;
- how users receive maintenance and completion notices; and
- where command output, timestamps, and decisions will be recorded.
Create and verify a new recovery set immediately before the upgrade. It must
contain the database, .env, complete storage/, any external
UPLOADS_DIR, site-owned files, infrastructure configuration, and old release
identity. Keep it separate from routine retention until the rollback window
has closed.
Confirm that enough free space exists for the new release, old release, backup, database growth during migration, new Twig cache, and logs. Confirm that backup decryption credentials and database restore privileges are available before writes are stopped.
Build or download the target release away from the live application root. For
example, replace 0.7.0 with the reviewed target version:
target_version='0.7.0'
composer create-project --no-dev --no-interaction \
bfhp/stream-engine /srv/stream-engine-next "$target_version"
cd /srv/stream-engine-next
composer check-platform-reqs --no-devThe target directory must be new and must not be served by the web server.
Compare its identity with the selected release. Retain its generated
composer.lock and vendor/; do not copy vendor/ from the old release and
do not run composer update in production.
Official release packages are expected to contain compiled frontend assets.
Production administrators should not run npm update. Run npm ci and
npm run build only when the release notes explicitly require a source build,
and build from that release's lockfile in a controlled build environment.
Before cutover, prepare how the new release will receive:
- the existing
.env, preservingAPP_SECRETand service credentials; - the complete existing
storage/, includinginstallation.json,migrations.json, and local uploads; - an external
UPLOADS_DIR, when configured; - custom themes through the configured
THEME_DIR; and - any other site-owned file declared by the deployment.
Use the site's tested deployment mechanism for shared directories or a consistent copy made while writers are stopped. Never replace the existing migration state with the empty/default state from a fresh release package. Never overlay a new release on the live tree one file at a time: removed files can remain behind and requests can observe a mixture of versions.
Memcached data and Twig's compiled templates are disposable. They must not force the new release to consume incompatible cached values.
Choose one of these tested approaches before deployment:
- invalidate only this site's cache namespace using the cache platform's supported tooling; or
- change
CACHE_PREFIXto a new site-and-release-specific value, then retain the old value in the rollback record.
Never flush a Memcached instance shared with other sites. A changed prefix leaves old keys to expire naturally, so include their temporary memory use in capacity planning.
For Twig, point TWIG_CACHE_DIR at a new, empty, writable directory for the
target release, or clear only the exact configured site cache using the
deployment's tested procedure. Restart or reload PHP-FPM after cutover so old
workers and opcode caches cannot continue serving old code. Do not delete the
general system temporary directory.
Use this order for both a traditional host and an orchestrated/container deployment. Platform-specific service commands belong in the site's runbook.
- Open the change record. Record the current and target releases, operator, start time, backup destination, and rollback deadline.
- Stop background work. Disable the external cron entry, stop the systemd timer, or scale the scheduler service to zero. Wait for an active task to finish; do not delete a lock to force it.
- Stop application writes. Make the reverse proxy or load balancer serve a maintenance response, drain active requests, and stop PHP-FPM or remove all application instances from service. Closing registration is not enough.
- Take the pre-upgrade recovery set. Follow the consistency procedure in the backup chapter and verify its database dump, archives, checksums, and release identity before proceeding.
-
Attach persistent state to the staged release. Copy or mount
.env, the completestorage/, uploads, and site-owned files while no writer is active. Merge only reviewed environment additions required by the target release; do not replace existing secrets with example values. Preserve ownership and restrictive permissions. -
Inspect migration state from the target root. Run
composer migrate:status. The pending list must match the rehearsal. An unexpected missing, renamed, changed, or additional file stops the change. -
Apply migrations once. Run
composer migrateas the deployment/service account. Save the complete output. On any error, do not start the site; enter the rollback procedure. -
Verify migration completion. Run
composer migrate:statusagain and requirePending: 0. - Switch the application release. Make the target code the only release reachable through the production application path. Do not start the old and new releases against the same database.
- Activate clean caches and PHP workers. Apply the prepared cache namespace and Twig path, then start or reload PHP-FPM.
- Test privately. Keep public traffic blocked while completing the smoke tests below through an operator-only route, direct backend address, or temporary access rule.
- Open traffic. Remove the maintenance response only after all required checks pass.
- Start exactly one scheduler. Restore the external runner, then confirm a recent Scheduler heartbeat and normal task history.
- Observe. Watch application, PHP-FPM, Nginx, the database, scheduler, email, capacity, and user reports through the rollback window.
For an immutable container deployment, build one image from the exact release, run migrations as a one-off job with the production state and database, and start web containers only after that job succeeds. Do not let every replica run migrations during startup. The included Docker Compose stack is a development environment; production orchestration and persistent-volume handling remain the operator's responsibility.
Record each result rather than relying on a single successful home-page load. At minimum:
-
composer check-platform-reqs --no-devsucceeds. -
composer migrate:statusreportsPending: 0. - The public home page and one representative content route return the expected page over HTTPS.
- An administrator can sign in and open the administration dashboard.
- Content, routes, menus, widgets, and the active theme render correctly.
- A representative role can access allowed content and is denied protected content.
- An existing local upload can be read; a disposable test upload can be created and removed when that workflow is in use.
- A controlled settings read and write succeeds without changing unrelated values.
- A test notification reaches the configured sink or approved recipient when mail behavior changed.
- The scheduler runs once, updates its heartbeat, and does not duplicate work.
- Application, PHP-FPM, web-server, database, and scheduler logs contain no new unexplained errors.
- Response time, database connections, cache use, disk space, and queue depth remain within the site's normal bounds.
Avoid destructive tests and avoid sending real bulk notifications during the maintenance window.
Rollback immediately when a migration fails, required state is missing, the new release cannot complete a critical workflow, or the cause of a serious error is not understood within the maintenance window. Extending an outage to experiment in production is not a recovery plan.
There are two different rollback cases:
If the database and persistent files have not changed, keep traffic and the scheduler stopped, switch back to the exact old release, restore its cache configuration, restart PHP-FPM, run the old release's smoke tests, and reopen traffic. Still preserve the failed staged release and logs for diagnosis.
An application-file switch alone is unsafe. The old code may not understand the new database schema, and a failed migration may have made unrecorded partial changes. Unless the release notes explicitly provide a tested backward-compatible path, restore the complete pre-upgrade recovery set.
- block public requests and stop all PHP-FPM and scheduler instances;
- preserve the failed database, release, migration output, and logs when this can be done without delaying recovery;
- make the exact old release the only deployable application code;
- restore the pre-upgrade database;
- restore the matching
.env, completestorage/, external uploads, and site-owned files from the same recovery set; - restore the old cache configuration, but start with disposable caches empty or isolated so failed-release entries are not reused;
- verify file ownership, permissions, PHP requirements, and
composer migrate:statusfrom the old application root; - start PHP-FPM and perform private smoke tests;
- reopen traffic, then start exactly one scheduler; and
- monitor the restored site and record the rollback finish time and data-loss boundary.
This restoration discards legitimate writes made after the recovery point. The maintenance procedure minimizes that loss by preventing public and background writes before the backup and keeping them blocked until the change is accepted.
Never point both old and new releases at the database to compare them. Never
manually delete migration records, reverse DDL by guesswork, or restore only
storage/migrations.json to make status output look correct. Migration state,
database schema, uploads, configuration, and code must describe the same
recovery point.
Keep the old artifact, pre-upgrade recovery set, command output, and failed
release if applicable until the documented observation and rollback periods
end. Then apply the normal retention policy; do not leave extra .env copies
or database dumps readable in application or web-accessible directories.
Record:
- actual start, migration, cutover, scheduler, and finish times;
- exact old and new release identities and checksums;
- backup identifier and verification result;
- migration files applied and their output;
- smoke-test results and observed metrics;
- every manual deviation and its approval; and
- follow-up work for release notes, automation, monitoring, or capacity.
- Target release and every intervening release note were reviewed.
- Runtime, database, custom theme, and integration compatibility passed.
- Upgrade and rollback succeeded against a recent isolated restore.
- Exact old and new artifacts are available and identifiable.
- Maintenance, communication, owners, and rollback deadline are agreed.
- A complete verified pre-upgrade recovery set exists off the application path.
- Scheduler and public writes are stopped before state is copied or changed.
- Target migration list matches rehearsal and migrations run exactly once.
- Migration status is clean, caches are isolated, and PHP workers are new.
- Private smoke tests pass before traffic and one scheduler are enabled.
- Monitoring remains active through the rollback window.
- Old release and recovery material remain available until change closure.
Back: Backups and restore · Administrator Guide · Next: Troubleshooting