feat(db): 7 MVP-1 migrations — UUID, tenant_id, role_user UNIQUE(user_id), parent_child no-tenant

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
Boban Blaskovic 2026-05-22 00:53:22 +02:00
parent af49f091f5
commit a198cd1fbe
7 changed files with 204 additions and 0 deletions

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('tenants', function (Blueprint $table) {
$table->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');
}
};

View File

@ -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) {

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('roles');
}
};

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('licenses', function (Blueprint $table) {
$table->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');
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('role_user', function (Blueprint $table) {
$table->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');
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('license_assignments', function (Blueprint $table) {
$table->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');
}
};

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('parent_child', function (Blueprint $table) {
$table->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');
}
};