id(); $table->foreignId('owner_user_id') ->constrained('users') ->cascadeOnDelete(); $table->string('name', 80); $table->string('slug', 90)->unique(); $table->string('headline', 160)->nullable(); $table->text('bio')->nullable(); $table->enum('visibility', ['public', 'private'])->default('public'); $table->string('website_url', 2048)->nullable(); $table->json('links_json')->nullable(); $table->string('avatar_path')->nullable(); $table->string('banner_path')->nullable(); $table->unsignedInteger('artworks_count')->default(0); $table->unsignedInteger('collections_count')->default(0); $table->unsignedInteger('followers_count')->default(0); $table->timestamp('last_activity_at')->nullable(); $table->timestamps(); $table->index(['visibility', 'followers_count']); $table->index(['owner_user_id', 'created_at']); }); Schema::create('group_members', function (Blueprint $table): void { $table->id(); $table->foreignId('group_id') ->constrained('groups') ->cascadeOnDelete(); $table->foreignId('user_id') ->constrained('users') ->cascadeOnDelete(); $table->foreignId('invited_by_user_id') ->nullable() ->constrained('users') ->nullOnDelete(); $table->enum('role', ['owner', 'admin', 'editor', 'member'])->default('member'); $table->enum('status', ['pending', 'active', 'revoked'])->default('pending'); $table->text('note')->nullable(); $table->timestamp('invited_at')->nullable(); $table->timestamp('expires_at')->nullable(); $table->timestamp('accepted_at')->nullable(); $table->timestamp('revoked_at')->nullable(); $table->timestamps(); $table->unique(['group_id', 'user_id'], 'group_members_group_user_unique'); $table->index(['group_id', 'status', 'role'], 'group_members_status_role_idx'); }); Schema::create('group_follows', function (Blueprint $table): void { $table->id(); $table->foreignId('group_id') ->constrained('groups') ->cascadeOnDelete(); $table->foreignId('user_id') ->constrained('users') ->cascadeOnDelete(); $table->timestamps(); $table->unique(['group_id', 'user_id'], 'group_follows_group_user_unique'); }); Schema::create('artwork_contributors', function (Blueprint $table): void { $table->id(); $table->foreignId('artwork_id') ->constrained('artworks') ->cascadeOnDelete(); $table->foreignId('user_id') ->constrained('users') ->cascadeOnDelete(); $table->unsignedInteger('sort_order')->default(0); $table->timestamps(); $table->unique(['artwork_id', 'user_id'], 'artwork_contributors_artwork_user_unique'); $table->index(['artwork_id', 'sort_order'], 'artwork_contributors_sort_idx'); }); } public function down(): void { Schema::dropIfExists('artwork_contributors'); Schema::dropIfExists('group_follows'); Schema::dropIfExists('group_members'); Schema::dropIfExists('groups'); } };