# ActivityEngine

> Generic activity log for all CRM entities. Models use `HasActivityTimeline`.
> No admin UI required — timeline is rendered inline in Show pages (Phase 2).

---

## Migration: `activity_logs`

```php
Schema::create('activity_logs', function (Blueprint $table) {
    $table->id();
    $table->morphs('subject');              // entity being acted on (lead, deal, contact)
    $table->string('action_type');          // 'created'|'updated'|'converted'|'auto_assign'|
                                            // 'stage_change'|'note_added'|'task_created'
    $table->json('meta')->nullable();       // arbitrary context ({contact_id, deal_id}, etc.)
    $table->foreignId('causer_id')->nullable()->constrained('users');
    $table->string('causer_type')->default('user');
    $table->timestamp('happened_at')->useCurrent();
    $table->timestamps();
    $table->index(['subject_type', 'subject_id', 'happened_at']);
});
```

---

## Trait: `HasActivityTimeline`

```php
// CoreApp/app/Traits/HasActivityTimeline.php
namespace CoreApp\Traits;

use CoreApp\Models\ActivityEngine\ActivityLog;

trait HasActivityTimeline
{
    public function activityLogs(): MorphMany
    {
        return $this->morphMany(ActivityLog::class, 'subject')
            ->orderByDesc('happened_at');
    }

    public function logActivity(string $actionType, array $meta = []): ActivityLog
    {
        return $this->activityLogs()->create([
            'action_type' => $actionType,
            'meta'        => $meta,
            'causer_id'   => auth()->id(),
        ]);
    }
}
```

---

## Required Log Points

| Where | action_type | meta fields |
|-------|-------------|-------------|
| Lead created | `created` | — |
| Lead converted | `conversion` | `{contact_id, deal_id}` |
| Stage moved | `stage_change` | `{from_stage_id, to_stage_id, reason}` |
| Auto-assigned | `auto_assign` | `{assigned_to, round_robin_index}` |
| Feature pack applied | logged to `settings` | `last_pack_applied = slug+timestamp` |
| Setup completed | logged to `settings` | `crm_setup_completed_at = now()` |

---

## Service: `ActivityService`

```php
// CoreApp/app/Services/ActivityEngine/ActivityService.php
class ActivityService
{
    /** Global feed — latest N activity entries across all entity types */
    public function globalFeed(int $limit = 50): Collection
    {
        return ActivityLog::with('causer')
            ->orderByDesc('happened_at')
            ->limit($limit)
            ->get();
    }

    /** Entity-scoped timeline — used in Show pages */
    public function forEntity(string $morphClass, int $id): Collection
    {
        return ActivityLog::where('subject_type', $morphClass)
            ->where('subject_id', $id)
            ->orderByDesc('happened_at')
            ->get();
    }
}
```
