- New BillingEvent enum replaces 'subscription.{created,updated,cancelled}'
strings across StripeEventListener, TrackBilling and tests.
- SendEvent now takes (method, payload) directly instead of an array of
single-call shapes — overhead with no batching benefit.
- PostHogService consolidates the 3 api-key short-circuits into shouldSend().
- SyncUser eager-loads currentWorkspace.withCount('socialAccounts') and
drops the redundant posts_count from the workspace group identify.
- Frontend Usage interface centralised in resources/js/types — was
duplicated in posthog.ts and useFeatureAccess.ts.
- posthog.init moved out of module-import side-effect into
initializePostHog() called explicitly from app.ts.
- SyncUserTest cleans up the convoluted assertion that merged
$job->calls with Queue::pushed().
- Drop tests/Feature/StripeEventListenerTest.php (orphan, fully covered
by tests/Feature/Listeners/StripeEventListenerTest.php).
- Revert .github/FUNDING.yml to match origin/main.
88 lines
2.3 KiB
PHP
88 lines
2.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Jobs\PostHog\SendEvent;
|
|
use App\Models\Account;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class PostHogService
|
|
{
|
|
/**
|
|
* Capture an event for the given distinct id. When `$account` is supplied,
|
|
* the workspace/plan group is auto-attached so the event is filterable in
|
|
* PostHog by `$groups.account` and the `account_id` / `plan` properties.
|
|
*
|
|
* @param array<string, mixed> $properties
|
|
*/
|
|
public function capture(string $distinctId, string $event, array $properties = [], ?Account $account = null): void
|
|
{
|
|
if (! $this->shouldSend()) {
|
|
return;
|
|
}
|
|
|
|
$payload = [
|
|
'distinctId' => $distinctId,
|
|
'event' => $event,
|
|
'properties' => $properties,
|
|
];
|
|
|
|
if ($account) {
|
|
$payload['properties']['$groups'] = ['account' => (string) $account->id];
|
|
$payload['properties']['account_id'] = (string) $account->id;
|
|
$payload['properties']['plan'] = $account->plan?->name;
|
|
}
|
|
|
|
$this->dispatch('capture', $payload);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $properties
|
|
*/
|
|
public function identify(string $distinctId, array $properties = []): void
|
|
{
|
|
if (! $this->shouldSend()) {
|
|
return;
|
|
}
|
|
|
|
$this->dispatch('identify', [
|
|
'distinctId' => $distinctId,
|
|
'properties' => $properties,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $properties
|
|
*/
|
|
public function groupIdentify(string $groupType, string $groupKey, array $properties = []): void
|
|
{
|
|
if (! $this->shouldSend()) {
|
|
return;
|
|
}
|
|
|
|
$this->dispatch('groupIdentify', [
|
|
'groupType' => $groupType,
|
|
'groupKey' => $groupKey,
|
|
'properties' => $properties,
|
|
]);
|
|
}
|
|
|
|
private function shouldSend(): bool
|
|
{
|
|
return (bool) config('services.posthog.api_key');
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $payload
|
|
*/
|
|
private function dispatch(string $method, array $payload): void
|
|
{
|
|
try {
|
|
SendEvent::dispatch($method, $payload);
|
|
} catch (\Throwable $e) {
|
|
Log::warning('PostHogService: failed to dispatch event', ['method' => $method, 'error' => $e->getMessage()]);
|
|
}
|
|
}
|
|
}
|