feat: add ClickHouse backups and cloud ops tools

Enable scheduled ClickHouse backups across the job, API, and UI, and
guard unsupported database types via isBackupSolutionAvailable().
Convert Stripe subscription sync from a job to an action with clearer
discrepancy resolution, and add cloud:export-users plus
cloud:cleanup-unverified-users with tests.
This commit is contained in:
Andras Bacsai committed 2026-07-16 11:57:52 +02:00
1 parent 908b5cc09d
commit 2719d66042
23 files changed
+1198 -71

No files matched your search

@@ -1,5 +1,6 @@
<?php
use App\Models\Subscription;
use App\Models\Team;
use Illuminate\Foundation\Testing\RefreshDatabase;
@@ -14,3 +15,24 @@ test('subscriptionEnded does not throw when team has no subscription', function
// If we reach here, no exception was thrown
expect(true)->toBeTrue();
});
test('subscriptionEnded updates the exact subscription when duplicate rows exist', function () {
$team = Team::factory()->create();
$otherSubscription = Subscription::create([
'team_id' => $team->id,
'stripe_subscription_id' => 'sub_other',
'stripe_invoice_paid' => true,
]);
$subscriptionToEnd = Subscription::create([
'team_id' => $team->id,
'stripe_subscription_id' => 'sub_stale',
'stripe_invoice_paid' => true,
]);
$team->subscriptionEnded($subscriptionToEnd);
expect($subscriptionToEnd->fresh()->stripe_subscription_id)->toBeNull()
->and($subscriptionToEnd->fresh()->stripe_invoice_paid)->toBeFalsy()
->and($otherSubscription->fresh()->stripe_subscription_id)->toBe('sub_other')
->and($otherSubscription->fresh()->stripe_invoice_paid)->toBeTruthy();
});