AI Skill Report Card

Building Realtime Chat Systems

A-85·Jun 6, 2026·Source: Web
15 / 15
PHP
// Database migration for conversation system Schema::create('conversations', function (Blueprint $table) { $table->id(); $table->enum('type', ['direct', 'group']); $table->string('title')->nullable(); $table->timestamps(); $table->index(['created_at']); }); Schema::create('conversation_user', function (Blueprint $table) { $table->id(); $table->foreignId('conversation_id')->constrained()->onDelete('cascade'); $table->foreignId('user_id')->constrained()->onDelete('cascade'); $table->enum('role', ['admin', 'member'])->default('member'); $table->timestamp('last_read_at')->nullable(); $table->timestamps(); $table->index(['conversation_id', 'user_id']); }); Schema::create('messages', function (Blueprint $table) { $table->id(); $table->foreignId('conversation_id')->constrained()->onDelete('cascade'); $table->foreignId('user_id')->constrained()->onDelete('cascade'); $table->text('content'); $table->json('metadata')->nullable(); // attachments, reply_to $table->timestamps(); $table->index(['conversation_id', 'created_at']); });
Recommendation
Add concrete input/output examples for WebSocket events and API responses to strengthen the examples section
13 / 15

Progress:

  • Design database schema with proper indexing
  • Set up WebSocket broadcasting with Laravel Reverb
  • Implement cursor pagination for message loading
  • Create optimistic UI updates on frontend
  • Add typing indicators and presence channels
  • Implement message delivery/read tracking
  • Set up background queues for media processing
  • Configure push notifications with FCM
  • Add Redis caching layer
  • Secure with proper authentication

1. Database Architecture

PHP
// Message tracking pivot table Schema::create('message_reads', function (Blueprint $table) { $table->id(); $table->foreignId('message_id')->constrained()->onDelete('cascade'); $table->foreignId('user_id')->constrained()->onDelete('cascade'); $table->timestamp('delivered_at')->nullable(); $table->timestamp('read_at')->nullable(); $table->unique(['message_id', 'user_id']); });

2. Real-time Broadcasting

PHP
// channels.php Broadcast::channel('conversation.{conversationId}', function ($user, $conversationId) { return $user->conversations()->where('conversation_id', $conversationId)->exists() ? ['id' => $user->id, 'name' => $user->name] : false; }); // Message sent event class MessageSent implements ShouldBroadcast { public function broadcastOn() { return new PresenceChannel('conversation.' . $this->message->conversation_id); } public function broadcastWith() { return [ 'message' => MessageResource::make($this->message), 'user' => UserResource::make($this->message->user) ]; } }

3. Cursor Pagination

PHP
// MessageController public function index(Request $request, Conversation $conversation) { $messages = $conversation->messages() ->with(['user', 'reads']) ->latest() ->cursorPaginate(50); return MessageResource::collection($messages); }

4. Frontend State Management (Vue + Pinia)

JavaScript
// stores/chat.js export const useChatStore = defineStore('chat', { state: () => ({ conversations: new Map(), currentConversation: null, typingUsers: new Set(), onlineUsers: new Set() }), actions: { sendMessage(content) { const tempId = `temp_${Date.now()}`; const optimisticMessage = { id: tempId, content, user: this.currentUser, status: 'sending', created_at: new Date().toISOString() }; this.addMessage(this.currentConversation.id, optimisticMessage); return this.api.sendMessage(this.currentConversation.id, content) .then(message => { this.replaceMessage(tempId, message); }) .catch(() => { this.removeMessage(tempId); }); } } });

5. Typing Indicators

PHP
// TypingEvent class UserTyping implements ShouldBroadcast { public function broadcastOn() { return new PresenceChannel('conversation.' . $this->conversationId); } public function broadcastAs() { return 'typing'; } } // Frontend let typingTimer; function handleTyping() { Echo.whisper('conversation.1', 'typing', { user_id: userId }); clearTimeout(typingTimer); typingTimer = setTimeout(() => { Echo.whisper('conversation.1', 'stopped-typing', { user_id: userId }); }, 3000); }
Recommendation
Include Redis configuration code and caching strategies in the workflow to make implementation more complete
15 / 20

Example 1: Message with Read Tracking Input: User sends "Hello world" in conversation Output:

JSON
{ "id": 123, "content": "Hello world", "user": { "id": 1, "name": "John" }, "reads": [ { "user_id": 2, "delivered_at": "2024-01-01T10:00:00Z", "read_at": null } ], "created_at": "2024-01-01T09:59:45Z" }

Example 2: Queue Job for Media Processing Input: User uploads image attachment

PHP
ProcessImageAttachment::dispatch($message, $uploadedFile) ->onQueue('media-processing');
Recommendation
Streamline the workflow section by removing some redundant explanations and focusing on the most critical implementation steps
  • Use cursor pagination to prevent message duplication during real-time updates
  • Implement optimistic UI updates for immediate user feedback
  • Cache online user status in Redis with TTL
  • Use presence channels for typing indicators and online status
  • Process media uploads in background queues
  • Encrypt sensitive message content at database level
  • Rate limit message sending (e.g., 10 messages per minute)
  • Use virtual scrolling for conversations with thousands of messages
  • Implement proper WebSocket reconnection logic
  • Store last read timestamps to calculate unread counts
  • Don't use regular pagination for real-time message loading
  • Don't store typing status in database - use Redis or memory
  • Don't broadcast to all users - use private/presence channels
  • Don't process large media files synchronously
  • Don't forget to clean up old WebSocket connections
  • Don't send full user objects in every message broadcast
  • Don't update read status on every message view
  • Don't use polling for real-time updates
  • Don't forget CSRF protection on WebSocket authentication
  • Don't store ephemeral data (typing, online status) permanently
0
Grade A-AI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
15/15
Workflow
13/15
Examples
15/20
Completeness
14/20
Format
15/15
Conciseness
13/15