Installation
composer require bkstg/timeline-bundle
Add to config/app.php under providers:
Backstage\TimelineBundle\TimelineBundle::class,
Publish Config
php artisan vendor:publish --provider="Backstage\TimelineBundle\TimelineBundle" --tag=config
Locate config at config/timeline.php.
First Use Case Create a timeline entry via CLI:
php artisan timeline:create --event="Project Kickoff" --description="Team alignment meeting" --user=1
Verify in database (timeline_events table) or via:
$events = \Backstage\TimelineBundle\Entity\TimelineEvent::all();
Event Creation
TimelineEvent entity with Eloquent:
$event = new \Backstage\TimelineBundle\Entity\TimelineEvent();
$event->event = "Code Review";
$event->description = "Review PR #42";
$event->user_id = auth()->id();
$event->save();
Issue::created):
use Backstage\TimelineBundle\Services\TimelineService;
class IssueObserver {
public function created(Issue $issue) {
app(TimelineService::class)->createEvent(
"Issue Created",
"Issue #{$issue->id} opened",
auth()->id(),
['issue_id' => $issue->id]
);
}
}
Displaying Timelines
Route::get('/timeline', [TimelineController::class, 'index']);
$events = app(\Backstage\TimelineBundle\Repository\TimelineEventRepository::class)
->findByUser(auth()->id(), 10); // Last 10 events
Render with Blade:
@foreach($events as $event)
<div class="timeline-item">
<h3>{{ $event->event }}</h3>
<p>{{ $event->description }}</p>
<small>{{ $event->created_at->diffForHumans() }}</small>
</div>
@endforeach
Filtering/Sorting
// Events for a project (custom metadata)
$events = $repo->findByMetadata('project_id', 5);
// Events between dates
$events = $repo->findBetween(
Carbon::yesterday(),
Carbon::tomorrow()
);
Metadata Handling
metadata field is stored as JSON. Ensure data is serializable:
// ❌ Fails: Circular reference
$event->metadata = ['user' => auth()->user()];
// ✅ Works: Use IDs or arrays
$event->metadata = ['user_id' => auth()->id()];
User Association
user_id is required but not validated by default. Add to your TimelineEvent model:
protected $with = ['user']; // Eager-load user
public function user() {
return $this->belongsTo(User::class);
}
CLI Command Quirks
timeline:create command lacks --metadata support. Extend it:
// app/Console/Commands/CreateTimelineEvent.php
protected $signature = 'timeline:create
{--metadata= : JSON metadata (e.g., --metadata={"key":"value"})}';
Missing Events?
Check timeline_events table and ensure:
user_id exists in users table.Performance
Add indexes to timeline_events(user_id, created_at):
php artisan schema:dump --prune
Then manually add:
Schema::table('timeline_events', function (Blueprint $table) {
$table->index(['user_id', 'created_at']);
});
Custom Event Types
Override the TimelineEvent entity or use traits:
namespace App\Entities;
use Backstage\TimelineBundle\Entity\TimelineEvent as BaseEvent;
class CustomTimelineEvent extends BaseEvent {
protected $casts = [
'priority' => 'integer', // Add custom fields
];
}
Webhook Integration
Listen for timeline.event.created events:
Event::listen('timeline.event.created', function ($event) {
// Send Slack notification, etc.
});
Testing
Use the TimelineEventFactory for fixtures:
$event = TimelineEventFactory::create()
->event('Deployment')
->user($user)
->create();
How can I help you explore Laravel packages today?