diff --git a/database/migrations/0001_01_01_000000_create_tenants_table.php b/database/migrations/0001_01_01_000000_create_tenants_table.php new file mode 100644 index 0000000..2218f54 --- /dev/null +++ b/database/migrations/0001_01_01_000000_create_tenants_table.php @@ -0,0 +1,32 @@ +id(); + $table->uuid('uuid')->unique(); + $table->string('name'); + $table->enum('type', ['school', 'private', 'system'])->default('private'); + $table->boolean('active')->default(true); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tenants'); + } +}; diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index 05fb5d9..2120856 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -13,12 +13,18 @@ return new class extends Migration { Schema::create('users', function (Blueprint $table) { $table->id(); + $table->uuid('uuid')->unique(); + $table->unsignedBigInteger('tenant_id'); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); + $table->softDeletes(); + + $table->foreign('tenant_id')->references('id')->on('tenants'); + $table->index('tenant_id'); }); Schema::create('password_reset_tokens', function (Blueprint $table) { diff --git a/database/migrations/2026_05_22_005034_create_roles_table.php b/database/migrations/2026_05_22_005034_create_roles_table.php new file mode 100644 index 0000000..87bd721 --- /dev/null +++ b/database/migrations/2026_05_22_005034_create_roles_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('name')->unique(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('roles'); + } +}; diff --git a/database/migrations/2026_05_22_005035_create_licenses_table.php b/database/migrations/2026_05_22_005035_create_licenses_table.php new file mode 100644 index 0000000..b590820 --- /dev/null +++ b/database/migrations/2026_05_22_005035_create_licenses_table.php @@ -0,0 +1,37 @@ +id(); + $table->uuid('uuid')->unique(); + $table->unsignedBigInteger('tenant_id'); + $table->enum('type', ['per_student', 'school_flat'])->default('per_student'); + $table->unsignedInteger('seats')->nullable(); + $table->date('expires_at')->nullable(); + $table->boolean('active')->default(true); + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('tenant_id')->references('id')->on('tenants'); + $table->index('tenant_id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('licenses'); + } +}; diff --git a/database/migrations/2026_05_22_005035_create_role_user_table.php b/database/migrations/2026_05_22_005035_create_role_user_table.php new file mode 100644 index 0000000..69efea5 --- /dev/null +++ b/database/migrations/2026_05_22_005035_create_role_user_table.php @@ -0,0 +1,33 @@ +id(); // AUTO_INCREMENT PK — NOT composite primary key + $table->unsignedBigInteger('role_id'); + $table->unsignedBigInteger('user_id'); + $table->timestamps(); + + $table->unique('user_id'); // 1 role per user enforced at DB level + $table->foreign('role_id')->references('id')->on('roles')->cascadeOnDelete(); + $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('role_user'); + } +}; diff --git a/database/migrations/2026_05_22_005036_create_license_assignments_table.php b/database/migrations/2026_05_22_005036_create_license_assignments_table.php new file mode 100644 index 0000000..b9bbfb3 --- /dev/null +++ b/database/migrations/2026_05_22_005036_create_license_assignments_table.php @@ -0,0 +1,33 @@ +id(); + $table->unsignedBigInteger('license_id'); + $table->unsignedBigInteger('user_id'); + $table->timestamps(); + + $table->unique(['license_id', 'user_id']); + $table->foreign('license_id')->references('id')->on('licenses')->cascadeOnDelete(); + $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('license_assignments'); + } +}; diff --git a/database/migrations/2026_05_22_005036_create_parent_child_table.php b/database/migrations/2026_05_22_005036_create_parent_child_table.php new file mode 100644 index 0000000..e3ca3fc --- /dev/null +++ b/database/migrations/2026_05_22_005036_create_parent_child_table.php @@ -0,0 +1,35 @@ +id(); + $table->uuid('uuid')->unique(); + // NO tenant_id — cross-tenant parent-child allowed (spec Option B) + $table->unsignedBigInteger('parent_id'); + $table->unsignedBigInteger('child_id'); + $table->timestamps(); + + $table->unique(['parent_id', 'child_id']); + $table->foreign('parent_id')->references('id')->on('users')->cascadeOnDelete(); + $table->foreign('child_id')->references('id')->on('users')->cascadeOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('parent_child'); + } +};