Skip to content

Activity Logging System - Cart Activities

Overview

This document explains how cart-related activities are logged using Spatie Activity Log and displayed in Filament.

Where to access

Activity logs are viewed in the EasyOTC admin panel:

SurfaceStaging URLLocal URL
Admin panel (Activity Logs)https://stage-api.easyotc.com/adminhttp://localhost:8000/admin

You must sign in with a user that holds the OTC_ONE_ADMIN role (see app/Enums/RoleEnum.php). See /access for the full URL and credential list.

Where this lives

  • Logging service: app/Services/AuditService.php
  • Auto-logging in cart flows: app/Services/CartItemService.php
  • Activity enum: app/Enums/ActivitiesEnum.php
  • Filament resources: app/Filament/Resources/ActivityResource.php, app/Filament/Resources/Products/RelationManagers/ActivitiesRelationManager.php, app/Filament/Resources/Users/RelationManagers/CartActivitiesRelationManager.php

Architecture & Design Decisions

The Challenge

When logging cart activities, we have 4 models involved:

  • User (Agent) - Who performs the action
  • Member - Whose cart is being modified
  • Cart - The shopping cart container
  • Product - The item being added/removed/updated

Spatie Activity Log only allows:

  • One causer (who did it)
  • One subject (what was affected)
  • Properties (additional data stored as JSON)

The Solution

We strategically chose which model to use as the subject based on query patterns:

ActivityCauserSubjectWhy Subject?
Cart Item AddedAgentProductQuery "cart history for this product"
Cart Item UpdatedAgentProductSame - product is the focus
Cart Item RemovedAgentProductSame - product is the focus
Cart CreatedAgentCartCart is the primary entity

Key Insight: We store all other IDs (member_id, cart_id, agent_id) in the properties JSON field for cross-referencing.

Database Structure

activity_log table (from Spatie):
├── id
├── log_name (e.g., 'cart_item_added')
├── description (human-readable)
├── subject_type (e.g., 'App\Models\Product')
├── subject_id (Product ID)
├── causer_type ('App\Models\User')
├── causer_id (Agent/User ID)
├── properties (JSON with cart_id, member_id, quantity, etc.)
└── created_at

Implementation

1. Logging Methods in AuditService

logCartItemAdded()

php
$auditService->logCartItemAdded(
    product: $product,           // Subject
    agent: $agent,               // Causer
    cartId: $cart->id,          // In properties
    memberId: $cart->member_id, // In properties
    quantity: $quantity,         // In properties
    purseId: $purseId,          // In properties
);

Stored As:

  • subject = Product model
  • causer = Agent/User model
  • properties = {cart_id, member_id, agent_id, quantity, purse_id, unit_price, total_price}

logCartItemUpdated()

Tracks quantity changes with old/new values.

logCartItemRemoved()

Logs when items are removed from cart.

logCartCreation()

Logs when a new cart is created for a member.

2. Automatic Logging in CartItemService

The CartItemService automatically logs activities:

php
public function addItem(Cart $cart, Product $product, ?int $purseId, int $quantity): CartItem
{
    // ... add logic ...

    // Automatically log the addition
    $this->auditService->logCartItemAdded(
        product: $product,
        agent: request()->user(),
        cartId: $cart->id,
        memberId: $cart->member_id,
        quantity: $quantity,
        purseId: $purseId
    );
}

No manual logging needed - it's built into the service methods!

3. Model Relationships

Product Model

php
public function activities()
{
    return $this->morphMany(Activity::class, 'subject');
}

User Model

php
public function causedActivities()
{
    return $this->morphMany(Activity::class, 'causer');
}

Viewing Activity in Filament

1. Product Cart History

When viewing a Product in Filament:

Products → View Product → "Cart Activity History" Tab

Shows:

  • ✅ All times this product was added to carts
  • ✅ Quantity updates for this product
  • ✅ Times this product was removed
  • ✅ Which agent performed each action
  • ✅ Which member's cart it was
  • ✅ When it happened

Filament File: app/Filament/Resources/Products/RelationManagers/ActivitiesRelationManager.php

2. Agent Activity

When viewing a User/Agent in Filament:

Users → View User → "Cart Activity (Agent Actions)" Tab

Shows:

  • ✅ All cart actions performed by this agent
  • ✅ Carts created by this agent
  • ✅ Items added/updated/removed by this agent
  • ✅ Which members they served
  • ✅ Which products they worked with

Filament File: app/Filament/Resources/Users/RelationManagers/CartActivitiesRelationManager.php

3. Global Activity Log

View ALL activities across the system:

Logs → Activity Logs

Filter by:

  • Log name (cart_item_added, cart_item_updated, etc.)
  • Date range
  • Subject type (Product, Cart, etc.)
  • Event type

Filament File: app/Filament/Resources/ActivityResource.php

Query Examples

Find All Cart Additions for a Product

php
use Spatie\Activitylog\Models\Activity;
use App\Enums\ActivitiesEnum;

$product = Product::find(1);

$additions = Activity::query()
    ->where('subject_type', Product::class)
    ->where('subject_id', $product->id)
    ->where('log_name', ActivitiesEnum::CART_ITEM_ADDED->value)
    ->get();

Find All Actions by an Agent

php
$agent = User::find(5);

$actions = Activity::query()
    ->where('causer_type', User::class)
    ->where('causer_id', $agent->id)
    ->whereIn('log_name', [
        ActivitiesEnum::CART_CREATION->value,
        ActivitiesEnum::CART_ITEM_ADDED->value,
        ActivitiesEnum::CART_ITEM_UPDATED->value,
        ActivitiesEnum::CART_ITEM_REMOVED->value,
    ])
    ->get();

Find All Activities for a Specific Member

php
$memberId = 10;

$memberActivities = Activity::query()
    ->whereIn('log_name', [
        ActivitiesEnum::CART_CREATION->value,
        ActivitiesEnum::CART_ITEM_ADDED->value,
        ActivitiesEnum::CART_ITEM_UPDATED->value,
        ActivitiesEnum::CART_ITEM_REMOVED->value,
    ])
    ->where('properties->member_id', $memberId)
    ->get();

Find All Activities for a Specific Cart

php
$cartId = 25;

$cartActivities = Activity::query()
    ->where('properties->cart_id', $cartId)
    ->orWhere(function ($query) use ($cartId) {
        $query->where('subject_type', Cart::class)
              ->where('subject_id', $cartId);
    })
    ->get();

Properties Schema

Cart Item Added

json
{
  "cart_id": 123,
  "member_id": 456,
  "agent_id": 789,
  "quantity": 2,
  "purse_id": 10,
  "unit_price": 1500,
  "total_price": 3000
}

Cart Item Updated

json
{
  "cart_id": 123,
  "member_id": 456,
  "agent_id": 789,
  "old_quantity": 2,
  "new_quantity": 5,
  "quantity_change": 3,
  "purse_id": 10,
  "unit_price": 1500
}

Cart Item Removed

json
{
  "cart_id": 123,
  "member_id": 456,
  "agent_id": 789,
  "quantity": 2,
  "cart_item_id": 999,
  "unit_price": 1500,
  "total_price": 3000
}

Cart Creation

json
{
  "member_id": 456,
  "agent_id": 789,
  "cart_uuid": "550e8400-e29b-41d4-a716-446655440000",
  "carrier_id": 5
}

Activity Enum

All cart activities are defined in app/Enums/ActivitiesEnum.php:

php
case CART_CREATION = 'cart_creation';
case CART_ITEM_ADDED = 'cart_item_added';
case CART_ITEM_UPDATED = 'cart_item_updated';
case CART_ITEM_REMOVED = 'cart_item_removed';

Each has:

  • label() - Display name
  • color() - Filament badge color
  • icon() - Heroicon for display

Benefits

Product-centric queries - Easily see cart history for any product ✅ Agent accountability - Track all actions by each agent ✅ Member activity - View all cart actions for a member ✅ Comprehensive audit trail - Full history with timestamps ✅ Filament integration - Beautiful UI without custom queries ✅ Automatic logging - No manual calls needed in controllers ✅ JSON properties - Flexible data storage for cross-referencing

Best Practices

  1. Always log through AuditService - Don't call activity() directly
  2. Use typed enums - Use ActivitiesEnum for consistency
  3. Include context in properties - Store IDs for cross-referencing
  4. Descriptive messages - Make description human-readable
  5. Query via relationships - Use $product->activities() when possible

Future Enhancements

If needed, you could add:

  • Statistics/analytics dashboards
  • Activity export functionality
  • Advanced filtering by date ranges
  • Member-specific activity views in MemberResource
  • Cart-specific activity views in CartResource
  • Real-time activity notifications
  • Activity rollback/undo features
  • app/Services/AuditService.php - Logging methods
  • app/Services/CartItemService.php - Automatic logging
  • app/Enums/ActivitiesEnum.php - Activity type definitions
  • app/Models/Product.php - Activities relationship
  • app/Models/User.php - Caused activities relationship
  • app/Filament/Resources/Products/RelationManagers/ActivitiesRelationManager.php
  • app/Filament/Resources/Users/RelationManagers/CartActivitiesRelationManager.php
  • app/Filament/Resources/ActivityResource.php - Global activity log