nawasara / sync
Foundation for the DB-cache + queue pattern shared across Nawasara service packages (WHM, Cloudflare, Keycloak, etc.) — sync job tracker, repository contract, snapshot trait, and audit UI.
v0.1.1
2026-05-10 14:21 UTC
Requires
- php: ^8.1
- illuminate/support: ^10.0|^12.0
- livewire/livewire: ^3.0
- nawasara/ui: *
- spatie/laravel-permission: ^6.0
README
The foundation package for the DB-cache + queue pattern used across every Nawasara service integration. Provides the sync-job tracker, repository contract, snapshot trait, audit log UI, and a system-health dashboard.
The pattern
External services (Cloudflare, WHM, Keycloak, etc.) are slow, rate-limited, and unreliable. Hitting them on every page render is wrong. Instead, every Nawasara service package follows this shape:
External API ◄───── Mutation Job (queue) ◄───── User action
│
▼ scheduled / on-demand sync
DB snapshot ─────► Repository ─────► Livewire page (paginated, fast)
- Reads come from a local snapshot table (paginated, indexed, fast)
- Writes dispatch queued mutation jobs that update the external API and the local snapshot atomically with content-hash conflict detection
- Audit log at
/admin/sync/jobsrecords every dispatched job (action, target, user, payload with sensitive fields masked, status, duration, error)
What this package ships
SyncJobmodel — the audit row for every queued action across every packageAbstractSyncJob— base for queued mutation/sync jobs. Auto-creates the tracker row in the constructor, marks it running/success/failed/conflict inhandle(), and masks sensitive payload keys (password, secret, token, key) before persistingSyncedRepositorycontract —list / find / all / create / update / delete / syncNow / lastSyncedAt. Every service package implements this consistentlyHasSyncStatustrait — addssync_status,sync_error,last_synced_at, andcontent_hashcolumns plus convenience scopes (pendingSync,failed,synced) and helpers (markPending,markSynced,markFailed)TracksLastSynctrait — repository helper that resolves the last successful sync time fromnawasara_sync_jobsinstead of from per-recordlast_synced_at(which only updates when content changes)<x-nawasara-sync::sync-badge>— pill component that visualises a row's sync state in tables- System Health at
/admin/sync/health— totals, per-service breakdown with success rate, recent failures, and a window switcher - Sync Jobs at
/admin/sync/jobs— searchable, filterable audit log with retry and detail modal
Installation
composer require nawasara/sync
php artisan migrate
php artisan db:seed --class="Nawasara\Sync\Database\Seeders\PermissionSeeder" --force
Auto-discovered.
Implementing a service package
use Nawasara\Sync\Concerns\HasSyncStatus; use Nawasara\Sync\Concerns\TracksLastSync; use Nawasara\Sync\Contracts\SyncedRepository; use Nawasara\Sync\Jobs\AbstractSyncJob; // 1. Snapshot model class WhmEmailAccount extends Model { use HasSyncStatus; public function computeContentHash(): string { return hash('sha256', json_encode([ 'email' => $this->email, 'quota_mb' => $this->quota_mb, // … fields you want to detect drift on ])); } } // 2. Repository class WhmEmailAccountRepository implements SyncedRepository { use TracksLastSync; public function list(array $filters = [], int $perPage = 25) { /* ... */ } public function create(array $data): ?SyncJob { /* dispatch CreateWhmEmailJob */ } public function update($id, array $data): ?SyncJob { /* dispatch ChangeWhmEmail*Job */ } public function delete($id): ?SyncJob { /* dispatch DeleteWhmEmailJob */ } public function syncNow(): ?SyncJob { /* dispatch SyncWhmEmailsJob */ } public function lastSyncedAt(): ?Carbon { return $this->lastSuccessfulSyncAt('whm', 'sync_emails'); } } // 3. Job class ChangeWhmEmailQuotaJob extends AbstractSyncJob { protected function service(): string { return 'whm'; } protected function action(): string { return 'quota_email'; } protected function targetType(): ?string { return 'WhmEmailAccount'; } protected function targetId(): ?string { return $this->payload['email']; } protected function execute(): array { // call external API… // update snapshot row… return ['quota_mb' => $newQuota]; } }
Permissions
| Permission | Description |
|---|---|
sync.job.view |
View sync jobs audit log |
sync.job.manage |
Retry or delete sync job rows |
Author
Pringgo J. Saputro <odyinggo@gmail.com>
License
MIT