Every non-interactive backup trigger used a slightly different path, so
final status and notification gating behaved inconsistently depending on
what started the backup (this is why pre-update backups did not gate
notifications the way "Backup Now" does).
Add src/Service/BackupRunner.php as the single synchronous entry point.
It delegates to BackupEngine (which already sends notifications gated by
the profile's notify_on_success/notify_on_failure and applies retention —
so there is exactly ONE notification layer), and normalises the result,
including the real complete/warning/fail status the engine records but did
not return. BackupRunner self-loads BackupEngine so callers require one file.
Routed through BackupRunner:
- plg_system runPreActionBackup() (preaction) + web-cron handler (webcron)
- plg_content triggerAutoBackup() (pre-install)
- plg_task scheduled task run
- plg_console RunCommand (cli)
The dashboard AJAX/stepped "Backup Now" flow is unchanged (it is the
interactive equivalent). The installer progress popup is deferred — the
installer request cannot drive the AJAX modal (TODO(#196) noted in code).
php -l clean on all changed files.
Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
Renames all sub-extensions from mokojoombackup to mokosuitebackup
(package, component, 7 plugins, language files, manifests).
Adds [HOME] placeholder to BackupDirectory and PlaceholderResolver
so users can set backup_dir to [HOME]/backups (outside web root).
Fixes folder browser "access denied" on PHP-FPM shared hosting
where getenv('HOME') returns empty by adding POSIX and JPATH_ROOT
fallback detection.