From a198cd1fbe8cb22dc5bff2f2f9e19cdd86bc043c Mon Sep 17 00:00:00 2001 From: Boban Blaskovic Date: Fri, 22 May 2026 00:53:22 +0200 Subject: [PATCH] =?UTF-8?q?feat(db):=207=20MVP-1=20migrations=20=E2=80=94?= =?UTF-8?q?=20UUID,=20tenant=5Fid,=20role=5Fuser=20UNIQUE(user=5Fid),=20pa?= =?UTF-8?q?rent=5Fchild=20no-tenant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- ...0001_01_01_000000_create_tenants_table.php | 32 ++++++++++++++++ .../0001_01_01_000000_create_users_table.php | 6 +++ .../2026_05_22_005034_create_roles_table.php | 28 ++++++++++++++ ...026_05_22_005035_create_licenses_table.php | 37 +++++++++++++++++++ ...26_05_22_005035_create_role_user_table.php | 33 +++++++++++++++++ ...05036_create_license_assignments_table.php | 33 +++++++++++++++++ ...05_22_005036_create_parent_child_table.php | 35 ++++++++++++++++++ 7 files changed, 204 insertions(+) create mode 100644 database/migrations/0001_01_01_000000_create_tenants_table.php create mode 100644 database/migrations/2026_05_22_005034_create_roles_table.php create mode 100644 database/migrations/2026_05_22_005035_create_licenses_table.php create mode 100644 database/migrations/2026_05_22_005035_create_role_user_table.php create mode 100644 database/migrations/2026_05_22_005036_create_license_assignments_table.php create mode 100644 database/migrations/2026_05_22_005036_create_parent_child_table.php 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'); + } +};