webteractive/filament-google-drive-backup-manager
A Filament plugin for managing Google Drive backups from your admin panel. Configure OAuth credentials, browse and create backups, monitor storage usage, and restore files without leaving Filament. Simple setup and a clean UI for effortless backup management.
Install and publish.
composer require webteractive/filament-google-drive-backup-manager
php artisan vendor:publish --tag="filament-google-drive-backup-manager-config"
Check whether the package ships migrations/config keys for storing the OAuth token; if so, run php artisan migrate.
Read the config file first. It is the map of the whole package: the Google client credentials (client_id, client_secret, redirect_uri), the target Drive folder ID, the retention count, and the backup source (database dump path / storage disks). Almost every "why didn't it work" question is answered by one of these keys.
Create the Google side before touching Filament. In Google Cloud Console: enable the Drive API, create an OAuth Web client, and add the package's callback URL as an authorized redirect URI. Put the credentials in .env — never in the committed config.
Register the plugin in your panel provider:
->plugin(GoogleDriveBackupManagerPlugin::make())
The plugin adds the settings/backup page where you connect the Google account and trigger an on-demand run.
First successful run = connect, then back up manually. Connect the account through the UI (that's what stores the access + refresh token), then hit the manual backup action and confirm you see the file in Drive. Only after that works should you wire up a schedule.
Then schedule it:
Schedule::command('...backup...')->daily()->at('02:00');
and point the scheduler at cron (* * * * * php artisan schedule:run). Verify with php artisan schedule:list rather than assuming.
Manual action as the smoke test, schedule as the real job. The Filament page action is a great first-run/debug path because it runs inside a normal web request (fresh process, fresh token). If manual works but the nightly run fails, the problem is almost always the worker environment — config, env vars, or a stale long-lived process — not the Google credentials.
Run the backup on a dedicated queue. Backups block on an HTTP upload; keep them off default so a slow Drive upload doesn't starve other jobs. Give the queue a worker with a sane --timeout and --tries=1 (a retried backup can duplicate files or hammer Drive's rate limits — make the job idempotent, or fail fast and alert).
Treat a disconnected Google account as an operational state, not an exception. Since v0.4.3 a dead/revoked refresh token throws an explicit "the stored Google account must be reconnected" error instead of a bare 401. Catch that case in your job (or in Filament's failed() hook) and route it to a notification/Slack channel plus a visible admin banner, because only a human can fix it by reconnecting. Distinguish it from transient failures (network, 5xx, rate limit) which should be retried with backoff.
Override per run, don't mutate the config at runtime. If you need different folders or retention per tenant/environment, do it through the documented per-run config path rather than editing the singleton config array — the package rebuilds the disk from config on each run, so runtime mutations outside that hook may not be picked up.
Keep secrets rotatable. Store client credentials in .env, run php artisan config:cache in deploy, and run php artisan queue:restart after any credential change so workers pick up the new env. A worker booted before the change keeps serving old config forever.
Local/CI strategy. Don't let tests or local dev hit the real Drive. In tests, Storage::fake() / a local disk stub and assert on the command/job being dispatched rather than the upload. For staging, use a separate Google account and a throwaway Drive folder so a misfired retention setting can't wipe production backups.
--max-time=0 reuses the gdbm disk — and the OAuth token minted at boot — until the process dies. Once the token expired (~1h) or the refresh token rotated, every backup 401'd even right after reconnecting. applyBackupConfig() now forgets the disk each run. Implication for you: never cache the gdbm disk yourself (app('filesystem')->disk('gdbm') stored on a singleton, in a service provider, or in a custom job's properties) — you'll reintroduce exactly this bug. Always resolve the disk inside the run.queue:work without --max-time, Octane. If you're on 0.4.2 or lower, this release is effectively a required upgrade for scheduled backups. Upgrade and queue:restart.refreshToken() returned an error array instead of throwing, so a revoked token looked identical to a Drive permission problem. Now you get a specific message; grep your logs for the reconnect phrasing before assuming a 401 is an API scope issue.php artisan <cmd> in the same container/queue config) → then check that the queue worker is running the new code (stale deploy is a common false positive).config:cache and .env. After any credential change on the server, re-cache config and restart workers — a cached config with old values reproduces the "I reconnected but it still fails" symptom without any token actually being revoked.How can I help you explore Laravel packages today?