All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
CronDescriberclass (moved from multiflexi-web5'sMultiFlexi\Uinamespace intoMultiFlexisomultiflexi-schedulercan use it too) — translates a RunTemplate interval code / cron expression into a short, localized sentence, including comma-separated hour lists (e.g.1 5,10,16,21 * * *→ "At minute 1 past hour 5, 10, 16, and 21.")RunTemplate::cloneAs()— cloning a RunTemplate now always creates the copy disabled (active=false), so a not-yet-reviewed copy of credentials/env/cron can never be picked up by the scheduler (#53)CredentialStateenum (Available/Degraded/Unavailable/Misconfigured/Unknown),CredentialCheckResult, andcheckableCredentialInterface— a live availability-check contract for credential prototypes.CredentialProtoTypeimplements it with a no-op default returningUnknown(backward compatible — existing prototypes never block).FioBankimplementscheckAvailability().Job::reportCredentialBlocked()— emits an availability-check failure to the SQL log, Zabbix (whenZABBIX_SERVERis configured), and OpenTelemetry (whenOTEL_ENABLED).Taskclass with a state machine (open/running/fulfilled/fulfilled_late/failed/missed) andmaterialize(),fulfill(),markFailed(),markMissed(),canRetry(),getNextRetryTime().Jobcarriestask_idand drives Task state transitions inrunEnd().RunTemplategains getters/setters fordeadline_offset,max_attempts,retry_backoff,retry_min_gap,allow_late.- Job-chaining support:
Applicationpersistsproduces/consumesfrom app.json import and exposesgetProduces()/getConsumes();Job::collectProducedData()resolves produced output by format;EventRule::buildEnvOverrides()generalized to accept any source array, plusresolveSelector()(dot-path/JSONPath/@file:) andgetRulesForRunTemplate()for job-completed chain triggers. CompanyUsermodel for company/user assignment handling.- Credential type SVG images (CommonCredentialType, Fio, Office365, SQLServer, env-file).
dragonmantank/cron-expressionis now a required dependency.
Application::deleteFromSQL()now refuses to delete (throws\RuntimeException) while any RunTemplate is still assigned to the app, instead of silently cascading to delete those RunTemplates itself. Callers must remove the RunTemplates first viaRunTemplate::deleteFromSQL(), which already cascades their jobs/config/credential bindings safely.Security\DataEncryptionwraps key-decryption failures in a dedicatedEncryptionUnavailableExceptionwith a diagnostic message naming the affected key/version, instead of a bare\RuntimeException— makes the common "ENCRYPTION_MASTER_KEYchanged/lost after theencryption_keysrow was created" case actionable from the error alone.
- Fixed
RunTemplate::deleteFromSQL()to correctly cascade-delete jobs (and their queue entries, output logs, and artifacts), action config, credential assignments, saved config values, and job-chaining event rules regardless of how it's called. Previously the cascade only worked when the object had been loaded with the target's own id; calling it with a condition array on an unloaded object (e.g.CompanyApp::assignApps()'s unassign path) silently skipped the cascade and then failed with an uncaught FK violation onjob.runtemplate_idfor any RunTemplate with job history.- Wrapped the cascade in a transaction so a failure partway rolls back cleanly instead of leaving orphaned dependents.
- Deactivates the RunTemplate first and re-sweeps job cleanup, to close a race window against the scheduler daemon inserting a new job mid-delete.
- Fixed array to string conversion for
requirementsandtopicsfields inApplication::importAppJson()- Arrays are now properly converted to comma-separated strings (e.g.,
["mServer", "SQLServer"]→"mServer,SQLServer") - Prevents "Array" string being stored in database during JSON imports
- Reimporting existing JSON files will now correctly update these fields with proper values
- Arrays are now properly converted to comma-separated strings (e.g.,
- Removed stale duplicate VaultWarden
CredentialProtoType(owned by the standalonemultiflexi-vaultwardenpackage; the copy here collided at install time) and leftover test files for credential types already split into their own add-on packages (multiflexi-abraflexi,multiflexi-csas,multiflexi-raiffeisenbank,multiflexi-mserver). Company::takeData()always setenabled=truewhen the key was present; now uses!empty()to respect the actual value.ConfigFieldtype normalization inCredential::takeData()andCredentialProtoType\Common::importFields()viaConffield::fixType().