@laracoft I usually base a chat off of 3 main tables (threads / participants / messages). I do set it up similar to you, however I use the participant to hold both "read at" and "muted". In general, a user will have many threads through participants, and I also do as you do and link the "owner" id on all sent messages.
Schema::create('threads', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('subject')->nullable();
$table->string('image')->nullable();
$table->timestamps();
$table->softDeletes();
});
Schema::create('participants', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->uuid('thread_id');
$table->unsignedBigInteger('user_id');
$table->boolean('muted')->default(0);
$table->timestamp('last_read')->nullable()->default(null);
$table->timestamps();
$table->softDeletes();
$table->foreign('thread_id')
->references('id')
->on('threads')
->onDelete('cascade')
->onUpdate('cascade');
});
Schema::create('messages', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->uuid('thread_id');
$table->unsignedBigInteger('user_id');
$table->integer('type')->index();
$table->text('body');
$table->timestamps();
$table->softDeletes();
$table->index('created_at');
$table->foreign('thread_id')
->references('id')
->on('threads')
->onDelete('cascade')
->onUpdate('cascade');
});
Muting wise I also check all participants I will broadcast to upon a new message / etc, so I use a scope on my $thread->participants()->notMuted() when gathering users to broadcast to (I prefer to broadcast messages over individual private channels).
You can also checkout a side project I am working on, and how I setup my full tables for chat: https://github.com/RTippin/messenger