This document describes the automated approval trail management system for archiving and cleaning up old approval trails.
The system provides automated tools to:
Important: The archiving job archives ALL approval trails older than the specified days, regardless of their approval order or overall status. This is different from the automatic archiving that only occurs when matrices are returned to draft/returned state.
php artisan approval:archive-trails
php artisan approval:archive-trails --matrix-id=123 --days=30 --dry-run
--matrix-id=N - Exclude matrix ID N from archiving (use "all" to archive all matrices)--days=N - Archive trails older than N days (default: 30)--dry-run - Show what would be archived without actually archiving--queue - Dispatch job to queue instead of running immediately# Archive ALL matrices older than 30 days
php artisan approval:archive-trails --matrix-id=all --days=30
# Archive trails older than 30 days, excluding matrix 123
php artisan approval:archive-trails --matrix-id=123 --days=30
# Dry run to see what would be archived (all matrices)
php artisan approval:archive-trails --matrix-id=all --days=30 --dry-run
# Archive very old trails (90+ days) via queue, excluding matrix 456
php artisan approval:archive-trails --matrix-id=456 --days=90 --queue
# Archive all matrices older than 7 days (immediate execution)
php artisan approval:archive-trails --matrix-id=all --days=7
php artisan approval:manage-trails stats
# Archive all matrices older than 30 days
php artisan approval:manage-trails archive --matrix-id=all --days=30
# Archive trails excluding matrix 123
php artisan approval:manage-trails archive --matrix-id=123 --days=30
php artisan approval:manage-trails cleanup --days=180 --force
When an approver converts a matrix line item to a single memo, the system copies activity_approval_trails into morph approval_trails for the Activity. Older conversions may still have matrix-style actions (passed, convert_to_single_memo) or wrong timestamps. This command repairs existing data.
Run from the apm/ directory.
# Preview changes (recommended first)
php artisan apm:fix-single-memo-promoted-approval-trails --dry-run
# Apply for all single-memo activities
php artisan apm:fix-single-memo-promoted-approval-trails
# One activity only
php artisan apm:fix-single-memo-promoted-approval-trails --activity-id=118 --dry-run
php artisan apm:fix-single-memo-promoted-approval-trails --activity-id=118
Options
| Option | Description |
|--------|-------------|
| --dry-run | List what would change; no writes |
| --activity-id= | Limit to one activity |
Behaviour summary
activities.is_single_memo is true.activity_approval_trails with approval_trails (same activity, model_type = Activity) by ascending id, for the first N rows where N = min(counts).passed → approved; convert_to_single_memo / converted_to_single_memo → returned.created_at / updated_at from the paired activity trail.Note: If extra approval_trails were inserted before or between promoted rows, index pairing may not match reality—use --activity-id and --dry-run to validate. New conversions use ActivityApprovalTrail::createPromotedApprovalTrail() so timestamps and mapped actions are written correctly at convert time.
See also: Jobs and Commands documentation (same command, full reference).
Automatically archives old approval trails for matrices and activities while excluding specified matrices.
- Approval order (0, 1, 2, 3, etc.)
- Overall status (draft, pending, approved, returned, etc.)
- Current workflow state
$excludeMatrixId - Matrix ID to exclude from archiving$daysOld - Number of days old to consider for archiving$dryRun - Whether to perform a dry runuse App\Jobs\ArchiveOldApprovalTrailsJob;
// Archive trails older than 30 days, excluding matrix 123
ArchiveOldApprovalTrailsJob::dispatch(123, 30, false);
// Dry run to see what would be archived
ArchiveOldApprovalTrailsJob::dispatch(null, 30, true);
Add to app/Console/Kernel.php:
protected function schedule(Schedule $schedule)
{
// Archive approval trails older than 30 days daily at 2 AM
$schedule->job(new ArchiveOldApprovalTrailsJob(null, 30, false))
->dailyAt('02:00')
->name('archive-approval-trails')
->withoutOverlapping();
}
// Clean up archived trails older than 180 days weekly
$schedule->command('approval:manage-trails cleanup --days=180 --force')
->weekly()
->sundays()
->at('03:00');
The stats action provides comprehensive information:
--dry-run flag--force to skip confirmations in scripts#!/bin/bash
# Daily approval trail maintenance
# Show current statistics
php artisan approval:manage-trails stats
# Archive old trails (exclude current active matrix 456)
php artisan approval:archive-trails --matrix-id=456 --days=30 --queue
# Check for very old archived trails
php artisan approval:manage-trails cleanup --days=180 --dry-run
# Force cleanup of very old archived trails
php artisan approval:manage-trails cleanup --days=365 --force
# Test archiving with dry run
php artisan approval:archive-trails --matrix-id=123 --days=7 --dry-run
# Test with immediate execution
php artisan approval:archive-trails --matrix-id=123 --days=7
- Ensure proper database permissions
- Check file system permissions for logs
- Use --queue for large operations
- Consider processing in smaller batches
- Ensure matrices exist before excluding them
- Check for orphaned activity trails
storage/logs/laravel.logis_archived = 0