The shop talks to a central Manage server (MANAGE_SERVER_URL) for three
things: it uploads backup archives there, it fetches release packages from
there, and it reports its status there. Everything is triggered from
Admin → Einstellungen (admin/settings.php); this host has no cron.
| File | Content |
|---|---|
includes/manage.php |
entry point: config defaults, HTTP transport, logging, version, manageClientStatus() |
includes/manage-zip.php |
pure-PHP ZIP writer used for backups |
includes/manage-backup.php |
collecting sources, writing archives, retention, upload |
includes/manage-update.php |
manifest, download, verification, deployment, migrations |
includes/manage-heartbeat.php |
status report to the Manage server |
includes/version.php |
the installed version, APP_VERSION |
includes/after-update.php |
shopAfterUpdate(), the post-update callback |
migrations/ |
migration scripts shipped inside a release, see migrations/README.md |
scripts/create-release-zip.sh |
builds a release package |
admin/settings.php |
the UI for all of it, plus admin account management |
Runtime state lives under data/manage/ and is gitignored:
backups/ (local archives + backup-index.json), updates/ (files the last
update overwrote), work/ (update staging, cleared after each run),
manage-client.log (JSONL), migrations.json, heartbeat.json.
config.php carries every MANAGE_* constant. See docs/CONFIG_REFERENCE.md;
defaults live in includes/manage.php, so config.php only has to set what
differs.
An archive contains data/*.json and assets/images/ — the operational data
and the product images uploaded through the admin UI, which exist nowhere else.
config.php is deliberately not in it: archives can be downloaded by anyone
with a Manage server login, and that file holds the legacy ADMIN_USERS
hashes, the order-history cookie secret and the instance token.
Three ways in:
manual.admin/index.php once
MANAGE_BACKUP_AUTO_INTERVAL_SECONDS (7 days) has passed since the last
automatic run — trigger automatic. The call returns immediately when nothing
is due, so the dashboard is only slow on the rare load that actually backs up.manageBackupCreate('manual') after
require_once includes/manage.php.Each archive is written to data/manage/backups/, then uploaded. The last
MANAGE_BACKUP_LOCAL_RETENTION (4) archives stay on disk; retention on the
Manage server is configured there and is usually much higher.
A failed upload does not invalidate the archive. The error is stored in the index record, shown in the Upload column and logged; the local ZIP is complete either way. A failure that does throw means the archive never came into being.
Concurrent runs are prevented by a lock file — a second one fails immediately with Es läuft bereits ein Backup.
Backups are created and transferred, never played back. Restoring means
downloading the ZIP from the settings page or the Manage server and unpacking it
over data/ and assets/images/ by hand. This is deliberate: an automated
restore button that runs while the shop is live is a footgun.
The settings page shows the installed version against the current release. The Update ausrollen button then:
.., an absolute path, a drive letter
or a null byte,MANAGE_UPDATE_SANITY_PATHS entry,
so an unrelated ZIP cannot be rolled over the shop,data/manage/updates/ first, skipping MANAGE_UPDATE_PROTECTED_PATHS,shopAfterUpdate().Take a backup first. The button does not do it for you — that stays a visible, deliberate act.
data/manage/updates/ are for manual
recovery, and only the most recent run is kept.MANAGE_UPDATE_PROTECTED_PATHS is config.php, data/, .git/. Note that
assets/images/ is not protected, and does not need to be: the updater only
touches paths contained in the package, so uploaded images survive on their own,
while a release can still ship or update its own images.
./scripts/create-release-zip.sh v1.1.0
The script writes the version into includes/version.php, packs every
git-tracked file minus config.php, data/, build/, scripts/ and
.codex/, and prints size and SHA-256. Commit the version bump, then upload the
ZIP in the Manage server under Releases.
Two things to get right:
PRODUCT at the top of the script must match MANAGE_PACKAGE_PREFIX on the
Manage server.vX.Y.Z. Forgetting to bump it means the
instance keeps reporting the old version and keeps being offered the same
update.Only committed content is packaged — the script warns on a dirty tree rather than refusing, because building from one is occasionally deliberate.
Reports version, PHP version, free disk space, pending migrations and the time
of the last backup. Without cron it rides along with page loads: at most once an
hour on the settings page (manageHeartbeatSendIfDue()), and immediately after a
backup or update, when those values have just changed. Status melden forces one.
It never breaks a page render — manageHeartbeatSendQuietly() swallows every
error into the log.
config.php,
which is gitignored and excluded from release packages. Rotate it on the Manage
server if it leaks.data/manage/ must not be web-readable. The root .htaccess denies all of
data/; verify with
curl -o /dev/null -w "%{http_code}\n" https://<host>/shop/data/manage/backups/
— anything but 403/404 is a problem. On nginx this needs a location rule
instead.backup-\d{8}-\d{6}(-\d+)?\.zip,
so the form cannot be made to serve another path.| Message | Cause |
|---|---|
| Der Manage-Client ist nicht konfiguriert. | MANAGE_SERVER_URL, MANAGE_INSTANCE or MANAGE_TOKEN empty in config.php |
| Es ist kein gültiges Release veröffentlicht. | no release published on the Manage server yet |
| Authentifizierung fehlgeschlagen. | wrong or rotated token; instance id typo |
| Die Prüfsumme des Pakets stimmt nicht überein. | corrupted download; nothing was deployed |
| Das Paket sieht nicht wie ein Release dieses Shops aus | packaged with a wrapping directory, or the wrong ZIP |
| Die Datei konnte nicht ausgerollt werden: … | PHP lacks write access in the shop root; the update stopped partway |
| Es läuft bereits ein Backup. | a second run while one is in progress |
data/manage/manage-client.log holds one JSON object per line for every backup,
update, migration and failure.