andreagroferreira/laravel-sync-tracker
Track and audit Eloquent model syncs with external systems (CRMs/ERPs/APIs). Store external IDs per source, sync status, timestamps, and metadata, and quickly find local models by external IDs—configurable for multiple integrations.
Installation:
composer require andreagroferreira/laravel-sync-tracker
Publish the config file:
php artisan vendor:publish --provider="AndreaGroferreira\SyncTracker\SyncTrackerServiceProvider" --tag="config"
Configuration:
config/sync-tracker.php for default settings (e.g., sync_models, sync_queues, redis_connection).sync_models array:
'sync_models' => [
\App\Models\User::class,
\App\Models\Product::class,
],
First Use Case:
Track a sync operation for a User model:
use AndreaGroferreira\SyncTracker\Facades\SyncTracker;
$user = \App\Models\User::find(1);
SyncTracker::track($user, 'sync_to_external_api', [
'source' => 'laravel',
'status' => 'pending',
'metadata' => ['user_id' => $user->id],
]);
Tracking Sync Operations:
SyncTracker::track() to log sync attempts:
SyncTracker::track($model, 'sync_operation_name', [
'status' => 'completed',
'attempts' => 3,
'last_error' => null,
]);
operation_name (e.g., sync_to_stripe, push_to_salesforce).Querying Sync Status:
$history = SyncTracker::history($user);
$failedSyncs = SyncTracker::history($user)
->where('status', 'failed')
->get();
Queue-Based Syncs:
SyncTracker::dispatchSyncJob():
SyncTracker::dispatchSyncJob($user, SyncToExternalApiJob::class, 'sync_to_external_api');
Model Observers:
SyncTrackerObserver for automatic tracking:
use AndreaGroferreira\SyncTracker\Observers\SyncTrackerObserver;
class UserObserver extends SyncTrackerObserver
{
public function syncing(User $user, string $operation)
{
// Custom logic before sync
}
public function synced(User $user, string $operation, array $result)
{
// Custom logic after sync
}
}
AppServiceProvider:
User::observe(SyncTrackerObserver::class);
Redis Stream Integration:
$consumer = app(\AndreaGroferreira\SyncTracker\Redis\SyncStreamConsumer::class);
$consumer->consume('sync-tracker-stream', function ($message) {
// Handle sync event (e.g., update UI, trigger alerts)
});
Sync Job Design:
SyncTrackerJob for custom jobs:
use AndreaGroferreira\SyncTracker\Jobs\SyncTrackerJob;
class SyncToStripeJob extends SyncTrackerJob
{
public function handle()
{
try {
$this->sync();
$this->markAsSynced();
} catch (\Exception $e) {
$this->markAsFailed($e->getMessage());
}
}
}
API Endpoints:
Route::get('/sync/status/{model}/{id}', function ($model, $id) {
$instance = app($model)->findOrFail($id);
return SyncTracker::history($instance)->latest()->first();
});
Webhook Triggers:
SyncTracker::triggerWebhook() to notify external systems:
SyncTracker::triggerWebhook($user, 'sync_completed', [
'url' => 'https://external-api.com/webhook',
'data' => ['user_id' => $user->id],
]);
Batch Processing:
SyncTracker::trackBatch($users, 'sync_all_users', [
'total' => $users->count(),
'completed' => 0,
]);
Redis Connection Issues:
redis_connection in config/sync-tracker.php matches your Laravel Redis config.redis-cli MONITOR
Model Not Tracked:
sync_models and the observer is registered.php artisan sync-tracker:install
Duplicate Entries:
operation_name + model_id combinations to avoid duplicates.uuid to metadata if needed:
SyncTracker::track($user, 'sync_to_api', [
'uuid' => Str::uuid()->toString(),
]);
Queue Stuck Jobs:
failed_jobs table and retry manually:
php artisan queue:retry all
Performance:
SyncTracker::bulkTrack() for high-volume operations:
SyncTracker::bulkTrack($users->toArray(), 'sync_users');
Log Sync Events:
'debug' => env('SYNC_TRACKER_DEBUG', false),
SyncTracker entries.Redis Stream Debugging:
redis-cli XGROUP LIST sync-tracker-stream consumer-group
redis-cli XREADGROUP GROUP consumer-group COUNT 1 BLOCK 0 STREAMS sync-tracker-stream 0
Query Builder:
SyncTracker::query() for custom queries:
$recentSyncs = SyncTracker::query()
->where('model_type', User::class)
->where('status', 'failed')
->where('created_at', '>', now()->subHours(1))
->get();
Custom Storage:
SyncTrackerRepository:
$this->app->bind(\AndreaGroferreira\SyncTracker\Repositories\SyncTrackerRepository::class, function ($app) {
return new CustomSyncTrackerRepository();
});
Event Listeners:
SyncTracked events:
event(new SyncTracked($user, 'sync_to_api', $data));
EventServiceProvider:
protected $listen = [
\AndreaGroferreira\SyncTracker\Events\SyncTracked::class => [
\App\Listeners\LogSyncEvent::class,
],
];
Custom Statuses:
status field with custom values (e.g., processing, queued):
SyncTracker::track($user, 'sync_to_api', ['status' => 'processing']);
Webhook Signatures:
SyncWebhookValidator:
class CustomWebhookValidator extends SyncWebhookValidator
{
public function validate(array $payload): bool
{
// Custom validation logic
return true;
}
}
AppServiceProvider:
$this->app->bind(\AndreaGroferreira\SyncTracker\Contracts\SyncWebhookValidator::class, CustomWebhookValidator::class);
How can I help you explore Laravel packages today?