This file provides guidance to WARP (warp.dev) when working with code in this repository.
MultiFlexi is a comprehensive PHP-based task scheduling and automation framework designed for accounting and business system integrations. The system follows a multi-component architecture:
- multiflexi-common: (This repository) Documentation, common assets, and Zabbix integration
- php-vitexsoftware-multiflexi-core: (External) The central library containing core functionality
- multiflexi-web: (External) Bootstrap 4 web interface with real-time monitoring
- multiflexi-cli: (External) Command-line interface for management operations
- multiflexi-scheduler: (External) Systemd service daemon that continuously schedules jobs
- multiflexi-executor: (External) Systemd service daemon that continuously executes scheduled jobs
- multiflexi-database: (External) Database schema and migration management
- multiflexi-server: (External) Optional server component for advanced deployments
- multiflexi-zabbix: (External) Zabbix integration components (moved from core)
- ansible-collection: (External) Ansible automation collection for infrastructure deployment
bin/: Common executables and Zabbix LLD launchersdebian/: Debian package build configuration for documentation and common assetsdocs/: Sphinx documentation sourcelib/: PHP scripts for Zabbix LLD and other common utilitieszabbix/: Zabbix templates and configuration filesgdpr/: GDPR compliance policies and documentationtools/: Miscellaneous helper scripts
MultiFlexi uses a layered architecture:
- Database Layer: ORM with Phinx migrations managing applications, companies, run templates, and jobs
- Application Management: External app definitions (.app.json files) with metadata validation
- Job Execution System: Multi-environment execution with environment variable injection
- Credential Framework: Extensible credential types for various system integrations
- Configuration Management: Environment-based configuration with type-safe field definitions
- Security Layer: Authentication, authorization, and secure credential handling
- Audit Trail: Job scheduling tracked by user (web or CLI) via
job.launched_byforeign key
Applications are defined using .app.json files that must conform to the schema at:
https://raw.githubusercontent.com/VitexSoftware/php-vitexsoftware-multiflexi-core/refs/heads/main/multiflexi.app.schema.json
Key elements:
executable: Command to runenvironment: Configuration fields with types (string, bool, number, password, file-path)requirements: System dependenciesociimage: Docker container image for containerized executionartifacts: Output files produced by the application
MultiFlexi tracks which user scheduled each job for accountability:
Database Schema:
job.launched_by(integer, NOT NULL, FK touser.id): User who scheduled the job- Migration:
20251121091900_job_launched_by_integer.php
User Types:
- Web Users (
user.enabled = 1): Users authenticated through web interface - CLI/OS Users (
user.enabled = 0): System users created automatically byUnixUserclass
How it Works:
- When jobs are scheduled via web interface,
\Ease\Shared::user()returns the authenticated web user - When jobs are scheduled via
multiflexi-cli, theUnixUserclass:- Detects the OS username via
get_current_user() - Checks if user exists in database
- Creates new user record with
enabled = 0if not found
- Detects the OS username via
- All jobs store user ID in
launched_bycolumn (never NULL)
UI Display:
- 👤 Web users shown with badge and link to user profile
- 🖥️ CLI users shown with secondary badge and link to auto-created profile
- User full name displayed if available, otherwise username
Scheduled jobs display their current position in the execution queue:
Visual Indicators:
- Scheduled Jobs: Blue badge showing position (#3/10 means 3rd out of 10 jobs)
- Orphaned Jobs: Warning badge (
⚠️ orphaned) for jobs without schedule entry
How it Works:
CompanyJobListerandDashboardRecentJobsTablequery all scheduled jobs ordered byschedule.after ASC- Build position map:
$scheduledCounts[$jobId] = $position - Display format: "💣 in 5 minutes #3/10" (scheduled time + queue position)
Code Locations:
CompanyJobLister::addSelectizeValues(): Queue position calculationCompanyJobLister::completeDataRow(): Display logic with badgesDashboardRecentJobsTable: Status badge with queue info
Code Locations:
- Core:
https://github.com/VitexSoftware/php-vitexsoftware-multiflexi-core - Web UI:
https://github.com/VitexSoftware/multiflexi-web - CLI:
https://github.com/VitexSoftware/multiflexi-cli - Zabbix Integration:
https://github.com/VitexSoftware/multiflexi-zabbix
IMPORTANT: Always use sudo mysql for direct database access to avoid repeated authentication attempts that waste AI credits.
# Access MultiFlexi database
sudo mysql
# Direct query execution
sudo mysql -e "USE multiflexi; DESCRIBE tablename;"
sudo mysql -e "USE multiflexi; SELECT * FROM user LIMIT 10;"
# Export database structure
sudo mysql multiflexi -e "SHOW CREATE TABLE runtemplate\G"Why sudo mysql:
- No password required (uses Unix socket authentication)
- Faster and more reliable than password-based authentication
- Avoids wasting resources on repeated connection attempts
- Standard approach for local MySQL administration on Debian/Ubuntu
The MultiFlexi REST API requires authentication for all endpoints (except /ping and /status).
Authentication Methods:
- HTTP Basic Authentication with username and password
- Token-based authentication (OAuth-style tokens)
- Session cookie authentication (for logged-in users)
Note: The API accepts session cookies from logged-in users, so JavaScript code on MultiFlexi pages does not require any special authentication mechanism - it automatically uses the user's existing session.
Create API user via multiflexi-cli:
# Create new user interactively
multiflexi-cli user:create
# Create user with parameters
multiflexi-cli user:create --login=apiuser --password=secret --email=api@example.com
# List existing users
multiflexi-cli user:list
# Generate API token for user
multiflexi-cli user:token --login=apiuserUsing HTTP Basic Authentication:
# Test with basic auth
curl -u username:password http://localhost/MultiFlexi/src/api/VitexSoftware/MultiFlexi/1.0.0/apps.json
# Test specific endpoint
curl -u username:password http://localhost/MultiFlexi/src/api/VitexSoftware/MultiFlexi/1.0.0/runtemplate/15.json
# With pretty-printed JSON output
curl -u username:password http://localhost/MultiFlexi/src/api/VitexSoftware/MultiFlexi/1.0.0/companies.json | python3 -m json.toolUsing Token Authentication:
# Get token
TOKEN=$(curl -s -u username:password http://localhost/MultiFlexi/src/api/VitexSoftware/MultiFlexi/1.0.0/login.json | jq -r .token)
# Use token in subsequent requests
curl -H "Authorization: Bearer $TOKEN" http://localhost/MultiFlexi/src/api/VitexSoftware/MultiFlexi/1.0.0/apps.jsonAPI Pagination Parameters:
All list endpoints support pagination:
limit- Maximum number of results (default: 20, max: 100)offset- Number of records to skip (default: 0)order- Field to sort by, use-prefix for descending (e.g.,-id)
# Get first 10 jobs
curl -u username:password "http://localhost/MultiFlexi/src/api/VitexSoftware/MultiFlexi/1.0.0/jobs.json?limit=10"
# Get next 10 jobs (pagination)
curl -u username:password "http://localhost/MultiFlexi/src/api/VitexSoftware/MultiFlexi/1.0.0/jobs.json?limit=10&offset=10"
# Get jobs ordered by ID descending
curl -u username:password "http://localhost/MultiFlexi/src/api/VitexSoftware/MultiFlexi/1.0.0/jobs.json?limit=10&order=-id"Using Session Cookies (JavaScript):
For JavaScript code running on MultiFlexi web pages, session cookie authentication is used automatically by the browser.
# Install dependencies
composer install
# Run all tests
make tests
vendor/bin/phpunit tests
# Run specific test configuration
vendor/bin/phpunit -c tests/configuration.xml tests/
# Static code analysis
make static-code-analysis
vendor/bin/phpstan analyse --configuration=phpstan-default.neon.dist --memory-limit=-1
# Generate static code analysis baseline
make static-code-analysis-baseline
# Code style fixing
make cs
vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --diff --verbose# Import application from JSON definition
multiflexi-cli application import-json --file path/to/app.json
# Validate application JSON schema
multiflexi-cli application validate-json --file multiflexi/app.app.json
# Export application to JSON
multiflexi-app2json
# Remove application
multiflexi-json-app-remover
# Generate job script with environment
multiflexi-job2script
# Import multiple applications
multiflexi-json2apps
### Data Retention Management (GDPR Phase 4)
```bash
# Calculate retention expiration dates
multiflexi-cli retention:cleanup calculate
# Run scheduled cleanup (with dry-run option)
multiflexi-cli retention:cleanup cleanup --dry-run
# Process grace period cleanup (final deletions)
multiflexi-cli retention:cleanup grace-period
# Clean up expired archives
multiflexi-cli retention:cleanup archive-cleanup --days=2555
# Generate compliance reports
multiflexi-cli retention:cleanup report --format=json --output=report.json
# Show retention status
multiflexi-cli retention:cleanup status
# Validate retention policies
multiflexi-cli application validate-json --file multiflexi/retention-policy.json
### Systemd Service Architecture (v2.x+)
MultiFlexi 2.x uses dedicated systemd services instead of cron:
```bash
# Control scheduler service
sudo systemctl start multiflexi-scheduler
sudo systemctl stop multiflexi-scheduler
sudo systemctl status multiflexi-scheduler
sudo systemctl restart multiflexi-scheduler
# Control executor service
sudo systemctl start multiflexi-executor
sudo systemctl stop multiflexi-executor
sudo systemctl status multiflexi-executor
sudo systemctl restart multiflexi-executor
# View service logs
sudo journalctl -u multiflexi-scheduler -f
sudo journalctl -u multiflexi-executor -f
# Development: Run daemons manually
make daemon # Run local daemon for testing
Service Configuration (/etc/multiflexi/multiflexi.env):
MULTIFLEXI_DAEMONIZE=true: Run continuously (default for services)MULTIFLEXI_CYCLE_PAUSE=10: Seconds between executor polling cyclesMULTIFLEXI_MEMORY_LIMIT_MB=1800: Soft memory limit for executor graceful shutdownMULTIFLEXI_MAX_PARALLEL=4: Maximum concurrent jobs (executor; requires pcntl)
# Clean build artifacts
make clean
# Update autoloader
make autoload
# Install probe application for testing
make probeapp
make instprobe# Build Debian packages
make debs
# Build and install locally
make redeb
# Create distribution packages
make debs2deb
# Build Docker images
make dimage # Main image
make demoimage # Demo image
make probeimage # Probe image
# Build multi-architecture probe image
make probeimagex# Run demo Docker container
make demorun
# Run main Docker container
make drunMultiFlexi automatically configures environment variables for executed applications:
ABRAFLEXI_URL: Server URLABRAFLEXI_LOGIN: UsernameABRAFLEXI_PASSWORD: PasswordABRAFLEXI_COMPANY: Company identifier
POHODA_ICO: Company ICO numberPOHODA_URL: Server URLPOHODA_USERNAME: UsernamePOHODA_PASSWORD: Password
MultiFlexi implements GDPR compliance in phases:
Phase 1: User consent and privacy management Phase 2: Data export and user rights (Article 15, 20) Phase 3: Security enhancements and access controls Phase 4: Data retention and automated deletion policies (Article 5(1)(e), 17)
SECURITY_AUDIT_ENABLED: Enable comprehensive security event logging (default: true)DATA_ENCRYPTION_ENABLED: Enable AES-256 data encryption (default: true)RATE_LIMITING_ENABLED: Enable API rate limiting (default: true)IP_WHITELIST_ENABLED: Enable IP whitelisting for admin access (default: false)ENCRYPTION_MASTER_KEY: Master encryption key (required for data encryption)
DATA_RETENTION_ENABLED: Enable automated data retention and cleanup (default: true)RETENTION_GRACE_PERIOD_DAYS: Default grace period before final deletion (default: 30)RETENTION_ARCHIVE_PATH: Path for archived data storage (default: /var/lib/multiflexi/archives)RETENTION_CLEANUP_SCHEDULE: Cron expression for automated cleanup (default: 0 2 * * *)
Most of the logic previously contained in this repository has been moved to specialized repositories:
- Web Interface & Widgets: Now in
multiflexi-web - CLI Commands: Now in
multiflexi-cli - Zabbix Integration: Now in
multiflexi-zabbix - Database Migrations: Now in
multiflexi-database
This repository (multiflexi-common) now serves as the central point for documentation and common assets that are shared across the ecosystem.
The project follows PSR-12 coding standards and includes:
- English comments and messages
- PHPStan static analysis (level 7)
- PHP-CS-Fixer for code formatting
- PHPUnit for testing
- Internationalization support using
_()functions
Property Declaration (Critical)
PHP 8.2+ requires all class properties to be explicitly declared before use. Dynamic property creation is deprecated and will cause warnings.
Common ORM Properties:
When extending classes that use \Ease\SQL\Orm trait, always declare these properties at the class level:
class MyClass extends \MultiFlexi\Engine
{
use \Ease\SQL\Orm;
/**
* Creation timestamp column name.
*/
public ?string $createColumn = null;
/**
* Last modified timestamp column name.
*/
public ?string $lastModifiedColumn = null;
public function __construct($identifier = null)
{
$this->myTable = 'my_table';
$this->createColumn = 'created_at';
$this->lastModifiedColumn = 'updated_at';
parent::__construct($identifier);
}
}Why This Matters:
- PHP's
__sleep()method (used for serialization) expects declared properties - Session storage and caching trigger object serialization
- Undeclared properties cause deprecation warnings in PHP 8.2+
- Will become fatal errors in PHP 9.0
Best Practices:
- Declare all properties at the class level with appropriate types
- Initialize nullable properties to
null - Set actual values in the constructor
- Never rely on dynamic property creation
- Run code on PHP 8.2+ during development to catch issues early
Test applications are located in the tests/ directory:
multiflexi_probe.multiflexi.app.json: Probe testing applicationsleep.multiflexi.app.json: Simple sleep test application
To validate application definitions against the schema, use:
multiflexi-cli application validate-json --file tests/multiflexi_probe.multiflexi.app.jsonTest security components with these commands:
# Test encryption functionality
php -r "echo MultiFlexi\Security\EncryptionHelpers::testEncryption() ? 'PASS' : 'FAIL'; echo PHP_EOL;"
# Check security audit logging
php -r "if(isset(\$GLOBALS['securityAuditLogger'])) { echo 'Security audit logger available'; } else { echo 'Not initialized'; }"
# Test rate limiting
php -r "echo MultiFlexi\Security\RateLimitHelpers::isRateLimitingAvailable() ? 'Available' : 'Disabled'; echo PHP_EOL;"
### Data Retention Testing (GDPR Phase 4)
Test data retention components with these commands:
```bash
# Test retention service initialization
php -r "use MultiFlexi\DataRetention\RetentionService; \$rs = new RetentionService(); echo 'Retention service: OK'; echo PHP_EOL;"
# Test policy validation
php -r "use MultiFlexi\DataRetention\RetentionPolicyManager; \$pm = new RetentionPolicyManager(); echo 'Policy manager: OK'; echo PHP_EOL;"
# Test data archiver functionality
php -r "use MultiFlexi\DataRetention\DataArchiver; \$da = new DataArchiver(); echo 'Data archiver: OK'; echo PHP_EOL;"
# Run retention system unit tests
vendor/bin/phpunit tests/DataRetention/RetentionServiceTest.php
### Application Import Behavior
MultiFlexi supports repeated application imports without database constraint violations. The import system:
1. **Identifies existing applications by UUID first, then by name as fallback**
2. **Cleanly replaces environment configurations** by deleting existing configs before inserting new ones
3. **Updates application metadata** instead of creating duplicates
4. **Handles translations** using `ON DUPLICATE KEY UPDATE`
This design allows packages to be reinstalled and application definitions to be updated seamlessly.
## Member Projects
MultiFlexi is part of a larger ecosystem of related projects:
- [multiflexi-scheduler](https://github.com/VitexSoftware/multiflexi-scheduler)
- [multiflexi-executor](https://github.com/VitexSoftware/multiflexi-executor)
- [php-vitexsoftware-multiflexi-core](https://github.com/VitexSoftware/php-vitexsoftware-multiflexi-core)
- [multiflexi-cli](https://github.com/VitexSoftware/multiflexi-cli)
- [multiflexi-database](https://github.com/VitexSoftware/multiflexi-database)
- [multiflexi-ansible-collection](https://github.com/VitexSoftware/multiflexi-ansible-collection)
- [multiflexi-web](https://github.com/VitexSoftware/multiflexi-web)
- [multiflexi-zabbix](https://github.com/VitexSoftware/multiflexi-zabbix)
When making changes, consider impacts on these related components and ensure compatibility across the ecosystem.
## GDPR Phase 4: Data Retention Administration
### Web Interface
Access the data retention administration interface at:
http://your-multiflexi-domain/data-retention-admin.php
**Features:**
- Policy management dashboard with real-time statistics
- Create, edit, delete, and toggle retention policies
- Quick actions for cleanup and retention calculations
- Visual overview of expired records awaiting cleanup
- Manual cleanup execution with dry-run capability
### Default Retention Policies
| Data Type | Retention Period | Action | Legal Basis |
|-----------|------------------|--------|-------------|
| User accounts (inactive) | 3 years | Anonymize | GDPR Art. 5(1)(e) |
| Session data | 30 days | Hard delete | Data minimization |
| Audit logs | 7 years | Archive | Legal requirements |
| Job execution logs | 1 year | Soft delete | Business operations |
| Application logs | 1 year | Hard delete | Troubleshooting |
| Company data | 5 years | Anonymize | Business relationships |
| Login attempts | 90 days | Hard delete | Security monitoring |
### Automated Scheduling
Add to crontab for automated cleanup:
```bash
# Daily cleanup at 2:00 AM
0 2 * * * /path/to/multiflexi-cli retention:cleanup cleanup
# Weekly grace period cleanup
0 3 * * 0 /path/to/multiflexi-cli retention:cleanup grace-period
# Monthly compliance reporting
0 9 1 * * /path/to/multiflexi-cli retention:cleanup report --format=json --output=/var/log/multiflexi/retention-report.json
Archive Management:
- Pre-deletion archives for 7 years (configurable)
- Legal hold capability for litigation/investigation
- Integrity verification with SHA-256 hashes
- Export capabilities (JSON, CSV formats)
Recovery Process:
- Grace periods before final deletion (default 30 days)
- Archive search and retrieval via CLI and web interface
- Verification of archived data integrity
- Legal hold extensions for compliance requirements