'array', ]; // ───────────────────────────────────────────────────────────────────────── // Action Constants — Workspace // ───────────────────────────────────────────────────────────────────────── public const ACTION_WORKSPACE_CREATED = 'workspace.created'; public const ACTION_WORKSPACE_UPDATED = 'workspace.updated'; public const ACTION_WORKSPACE_DELETED = 'workspace.deleted'; public const ACTION_WORKSPACE_SETTINGS_CHANGED = 'workspace.settings_changed'; // ───────────────────────────────────────────────────────────────────────── // Action Constants — Membership // ───────────────────────────────────────────────────────────────────────── public const ACTION_MEMBER_INVITED = 'member.invited'; public const ACTION_MEMBER_JOINED = 'member.joined'; public const ACTION_MEMBER_REMOVED = 'member.removed'; public const ACTION_MEMBER_ROLE_CHANGED = 'member.role_changed'; public const ACTION_MEMBER_TEAM_CHANGED = 'member.team_changed'; // ───────────────────────────────────────────────────────────────────────── // Action Constants — Entitlements // ───────────────────────────────────────────────────────────────────────── public const ACTION_PACKAGE_ASSIGNED = 'package.assigned'; public const ACTION_PACKAGE_REMOVED = 'package.removed'; public const ACTION_BOOST_APPLIED = 'boost.applied'; public const ACTION_BOOST_REMOVED = 'boost.removed'; // ───────────────────────────────────────────────────────────────────────── // Action Constants — Security Events // ───────────────────────────────────────────────────────────────────────── public const ACTION_API_KEY_CREATED = 'api_key.created'; public const ACTION_API_KEY_REVOKED = 'api_key.revoked'; public const ACTION_WEBHOOK_CREATED = 'webhook.created'; public const ACTION_WEBHOOK_DELETED = 'webhook.deleted'; // ───────────────────────────────────────────────────────────────────────── // Relationships // ───────────────────────────────────────────────────────────────────────── /** * The workspace this activity belongs to. */ public function workspace(): BelongsTo { return $this->belongsTo(Workspace::class); } /** * The user who performed this action. */ public function user(): BelongsTo { return $this->belongsTo(User::class); } /** * The subject (polymorphic) of this activity. */ public function subject(): MorphTo { return $this->morphTo(); } // ───────────────────────────────────────────────────────────────────────── // Scopes // ───────────────────────────────────────────────────────────────────────── /** * Scope to a specific workspace. */ public function scopeForWorkspace($query, Workspace|int $workspace) { $workspaceId = $workspace instanceof Workspace ? $workspace->id : $workspace; return $query->where('workspace_id', $workspaceId); } /** * Scope to a specific action. */ public function scopeForAction($query, string $action) { return $query->where('action', $action); } /** * Scope to a specific action prefix (e.g. 'member.' matches all member actions). */ public function scopeForActionGroup($query, string $prefix) { return $query->where('action', 'like', $prefix . '%'); } /** * Scope to a specific subject. */ public function scopeForSubject($query, Model $subject) { return $query ->where('subject_type', $subject->getMorphClass()) ->where('subject_id', $subject->getKey()); } /** * Scope to a specific user. */ public function scopeByUser($query, User|int $user) { $userId = $user instanceof User ? $user->id : $user; return $query->where('user_id', $userId); } /** * Scope to activities within a date range. */ public function scopeBetween($query, $from, $to) { return $query->whereBetween('created_at', [$from, $to]); } /** * Order by most recent first. */ public function scopeLatestFirst($query) { return $query->orderByDesc('created_at'); } // ───────────────────────────────────────────────────────────────────────── // Factory Methods // ───────────────────────────────────────────────────────────────────────── /** * Record a workspace activity. */ public static function record( Workspace|int $workspace, string $action, ?Model $subject = null, ?User $user = null, ?array $metadata = null, ): self { $workspaceId = $workspace instanceof Workspace ? $workspace->id : $workspace; return self::create([ 'workspace_id' => $workspaceId, 'user_id' => $user?->id ?? auth()->id(), 'action' => $action, 'subject_type' => $subject?->getMorphClass(), 'subject_id' => $subject?->getKey(), 'metadata' => $metadata, ]); } /** * Record a membership change. */ public static function recordMembershipChange( Workspace|int $workspace, string $action, WorkspaceMember|User $subject, ?User $performedBy = null, ?array $metadata = null, ): self { return self::record($workspace, $action, $subject, $performedBy, $metadata); } /** * Record an entitlement change. */ public static function recordEntitlementChange( Workspace|int $workspace, string $action, Model $subject, ?User $performedBy = null, ?array $metadata = null, ): self { return self::record($workspace, $action, $subject, $performedBy, $metadata); } /** * Record a security event. */ public static function recordSecurityEvent( Workspace|int $workspace, string $action, ?Model $subject = null, ?User $performedBy = null, ?array $metadata = null, ): self { return self::record($workspace, $action, $subject, $performedBy, $metadata); } }