Make 'beta' the canonical update_channel value across the settings UI,
GitHubReleases (prerelease filter + cache-file suffix + setChannel), the
binary/fanout update commands, and the module channel mapping.
'unstable' is kept as a legacy alias so nothing breaks mid-upgrade:
GitHubReleases::normalizeChannel() maps it to 'beta', and the binary commands
still accept it. Migration 011 rewrites existing settings.update_channel
'unstable' -> 'beta', and the settings dropdown normalizes a stale 'unstable' to
show Beta selected before the migration runs. Docs (en) updated.
Adds a "safety net" rollback so a server can be downgraded to an earlier
release without a manual redeploy, mirroring the existing update flow.
- GitHubReleases: getVersionFile() fetches a specific version's asset (not
just latest); getPreviousVersions() lists the newest releases older than a
given version, each flagged beta (GitHub prerelease). getReleases() now
delegates to a shared getFilteredReleases() that keeps the prerelease flag.
- UpdateCommand: new `rollback <version>` case — validates the target is a
real, strictly-older release; on MAIN takes an automatic DB backup first
(aborting if it fails); downloads the exact version (main/lb_update asset),
verifies MD5, and hands off to the same python `update` applier.
- RootSignalsCronJob: dispatch the `rollback` signal to `console.php update
rollback <version>` (version regex-validated, escapeshellarg'd).
- api.php: `rollback_versions` (channel-aware list, optional per-server base
version) and server `sub=rollback` (validates version, writes the signal).
- servers.php: per-server "Rollback Version" action (dropdown item + button)
opening a modal to pick a version; beta builds show "(beta)". Works for
MAIN and each LB independently.
- docs: rollback sections in server-update.md and update-system.md.
The downgrade reuses the version-agnostic python applier, so binaries,
config and user data are preserved. Migrations are forward-only and are not
rolled back; the automatic MAIN backup is the recovery path.
Replace the hand-maintained Docsify site (parallel docs/en + docs/ru trees
that had already drifted) with a MkDocs Material build where English is the
single source of truth and Russian is generated at build time.
Engine & structure
- mkdocs.yml: Material theme, site_url for the /XC_VM/ Pages subpath, and a
two-tab information architecture — User Guide (administration, API/Swagger,
UI translations, diagnostics, info/FAQ) vs Developer Guide (architecture,
workflow, security, integrations, build). Files are NOT moved — the split is
nav-only, so URLs and cross-links stay stable.
- mkdocs-static-i18n (folder mode): English at root, Russian under /ru/, with a
language switcher. `mkdocs build --strict` validates every link/anchor.
Translation pipeline (tools/docs/translate.py)
- Engine-agnostic via DOCS_TRANSLATE_PROVIDER: translators (free, no API key —
default), anthropic, deepl, or noop. Per-file sha256 cache so only changed
English files are re-translated. Markdown-safe: code, URLs, HTML tags and
glossary terms (XC_VM, FFmpeg, HLS, ...) are masked and never translated.
A file whose translation fails falls back to English so the build never breaks.
- docs/ru is generated and gitignored — never committed. It is produced locally
(`make docs-serve` / `docs-build`) and in CI.
CI & tooling
- pages.yml: build-then-upload (setup-python -> install -> restore .docs-cache
with restore-keys -> translate -> mkdocs build --strict -> deploy), replacing
the verbatim docs/ upload.
- Makefile: docs-venv / docs-translate / docs-build / docs-serve.
- docs/requirements.txt; .gitignore for docs/ru, site/, .docs-cache.
Migration details
- Removed Docsify control files (index.html, _navbar.md, _sidebar.md, .nojekyll)
and de-Docsify-ed body links in 6 English files (en-us/ aliases -> relative,
swagger _media paths, stripped ':ignore' link syntax).
- Preserved the two Russian-only planning docs (no English source) by moving
them into docs/adr/ as *.ru.md (repo-internal, excluded from the site).
update-system.md and faq.md (ru+en) linked to <lang>/development/cli-tools.md,
but the file lives at <lang>/guides/cli-tools.md (as the sidebar already points) —
the old path rendered an empty docsify page. Also repoint two non-existent anchors
(#миграции-базы-данных, #database-migrations) to the real section
(#обновление-бд-после-обновления-версии / #database-updates-after-version-upgrade).
Overhaul the Docsify documentation (English + Russian) so it matches the current
codebase and follows one consistent pattern.
Content accuracy (post-migration):
- Rewrite development/autoloader.md to PSR-4 / Composer (the old XC_Autoloader
scanner, igbinary tmp/cache/autoload_map and registerDirectories are gone).
- PascalCase every source path (src/core -> src/Core, domain/Stream, cli/Commands,
public/Controllers, Infrastructure/Redis, ...) across all docs.
- Replace the removed autoload.php references with vendor/autoload.php
(build_system, bootstrap-contexts, error-handling, modules).
- ssl-generation: note that the installer now auto-generates a unique self-signed
certificate before Nginx starts.
Common pattern (Clean & uniform):
- Strip emoji from headings; remove the in-page Navigation blocks (the Docsify
sidebar already provides navigation).
- One H1 + intro per doc; uniform "Related files" / "Связанные файлы" section,
added to the code-centric docs that lacked it.
Structure:
- Remove the empty stray docs/api/; move updates_checklist.md into builds/;
link the previously-orphaned ucs-integration.md.
- Regroup the sidebars (split the oversized guides group into Developer Guides /
Security & Access / Integrations; fold builds into Build & Release).
Augment:
- dev-workflow: Local Setup (make dev-tools) + Quality Checks (phpstan, cs, gates).
- build_system: Composer Dependencies section (committed prod-only vendor,
committed lock, dev tools via composer install, no build-time vendor step).
en/ru parity:
- Apply the same structure, fixes and pattern to docs/ru/ (translated), including
a new Russian ucs-integration.md. The en and ru file sets are now identical.
Replace separate install/update build targets with a single archive that
serves both purposes. The update script (src/update) now extracts to a
temp directory, removes excluded dirs (binaries, config, user data), and
copies remaining files over the live installation.
Changes:
- Remove main_update, lb_update, lb_update_copy_files,
main_update_copy_files Makefile targets and UPDATE_EXCLUDE_DIRS var
- Move exclude dirs list into src/update (Python) where filtering
actually happens at runtime
- Rewrite doUpdate() to use tempdir extraction with try/finally cleanup
- Make delete_files_list/lb_delete_files_list gracefully skip when
LAST_TAG is empty (warn instead of error)
- Simplify CI workflows: one make command per variant instead of
conditional install + update steps
- Add ARCHITECTURE.md §5.5 documenting update flow
- Update en/ru docs: update-system.md, updates_checklist.md
- Update makefile-build.instructions.md with new targets