История коммитов

.
feat(admin): add maintenance tasks page to run console commands
Introduce a universal admin page that lists console commands marked with
the new #[AsAdminTask] attribute and runs them in two modes:

- foreground tasks (e.g. cache:clear) run synchronously in the request;
- background tasks (e.g. sitemap:generate) are queued to a file-based
store and picked up by the existing cron scheduler within a minute
via the new admin-tasks:run-queued command.

Queue and lock files live under data/admin_tasks (outside CACHE_PATH so
cache:clear cannot wipe them). Overlap is guarded by a flock mutex.

New route (rights >= 9): /admin/maintenance, sidebar link with a new
#[tool] sprite icon, and en/ru locale strings.
.
feat(downloads): add sitemap URL provider
Register a SitemapUrlProviderInterface implementation for the downloads module that emits category and approved file URLs into the generated sitemap.
.
feat(library): add sitemap URL provider
Register a SitemapUrlProviderInterface implementation for the library module that emits category and published article URLs into the generated sitemap.
.
docs: update docs submodule with forum link normalization guide
.
docs(changelog): add entry for forum normalize-message-links command
.
feat(forum): add command to normalize legacy links in message text
Adds forum:normalize-message-links, a one-time console command that unwraps
the /redirect/ interstitial from internal links in forum posts and rewrites
legacy links to canonical routes:
- ?act=show_post&id=N -> /forum/post/N/
- ?type=topic&id=N[&page=P] -> SEO url via ForumTopicPathService

External links stay wrapped. Link rewriting lives in a pure, tested
ForumMessageLinkNormalizer service.
.
refactor(system): use Cache library for counters
- Replace manual file cache (file_exists/filemtime/json_decode/file_put_contents) with Johncms\Cache remember()
- Merge duplicated counter queries: album/downloads/library/forum pairs now share one cached raw method and a single cache key
- Fix warning on accessing array offset on null when a cache file was empty or corrupted
- Drop unused Tools dependency from Counters constructor
.
fix(system): handle null path from parse_url in UserStat::determinePlace
Protocol-relative request URIs like //x.php are parsed as host without path, making parse_url return null and str_ireplace throw a TypeError.
.
feat(collections): add standalone install script for existing setups
- install/install_collections.php creates the 5 module tables via ModuleInstaller
- idempotent: skips when the collections table already exists
- optional --demo flag installs the sample "Blog" collection
- document the step in the 9.8 upgrade guide and CHANGELOG
.
fix(system): restore HTMLPurifier factory for global \HTMLPurifier service
The plain class registration overrode the factory definition, so the
container returned a default HTMLPurifier without figure/oembed/figcaption
support. Rich content images lost their figure.image wrapper, breaking
in-container image scaling and the magnific popup.

Closes #254