> */ public const TIERS = [ 'standard' => [ 'participant_minutes' => 10000, 'recording_storage_bytes' => 5_368_709_120, // 5 GB 'ai_minutes' => 120, ], 'professional' => [ 'participant_minutes' => 50000, 'recording_storage_bytes' => 26_843_545_600, // 25 GB 'ai_minutes' => 600, ], 'enterprise' => [ 'participant_minutes' => 500000, 'recording_storage_bytes' => 107_374_182_400, // 100 GB 'ai_minutes' => 5000, ], ]; public function quotas(Organization $organization): array { $tier = $organization->license_tier ?? 'standard'; $defaults = self::TIERS[$tier] ?? self::TIERS['standard']; return array_merge($defaults, (array) ($organization->usage_quotas ?? [])); } public function withinQuota(Organization $organization, string $metric, int $additional = 0, ?int $branchId = null): bool { $quotas = $this->quotas($organization); $limit = (int) ($quotas[$metric] ?? 0); if ($limit <= 0) { return true; } $since = now()->startOfMonth(); $query = UsageRecord::where('organization_id', $organization->id) ->where('metric', $metric) ->where('recorded_at', '>=', $since); if ($branchId) { $query->where('branch_id', $branchId); } $used = (int) $query->sum('quantity'); return ($used + $additional) <= $limit; } public function assertCanStartSession(Organization $organization, ?int $branchId = null): void { abort_unless( $this->withinQuota($organization, 'participant_minutes', 60, $branchId), 402, 'Participant-minute quota exceeded for this billing period.', ); } }