Testing Alpha
This commit is contained in:
@ -1,9 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\{DB,Schema};
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
@ -19,9 +18,12 @@ return new class extends Migration
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('last_name', 100)->nullable()->comment('Apellidos')->index()->after('name');
|
||||
$table->string('profile_photo_path', 2048)->nullable()->after('remember_token');
|
||||
$table->unsignedTinyInteger('status')->default(User::STATUS_DISABLED)->after('profile_photo_path');
|
||||
$table->boolean('status')->default(1)->after('profile_photo_path');
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index()->after('status');
|
||||
|
||||
// Auditoria
|
||||
$table->softDeletes();
|
||||
|
||||
// Definir la relación con created_by
|
||||
$table->foreign('created_by')->references('id')->on('users')->onUpdate('restrict')->onDelete('restrict');
|
||||
});
|
||||
@ -35,10 +37,5 @@ return new class extends Migration
|
||||
DB::statement('ALTER TABLE `users` MODIFY `id` MEDIUMINT UNSIGNED NOT NULL;');
|
||||
DB::statement('ALTER TABLE `users` DROP PRIMARY KEY;');
|
||||
DB::statement('ALTER TABLE `users` MODIFY `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY (`id`);');
|
||||
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn(['last_name', 'profile_photo_path', 'status', 'created_by']);
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Koneko\VuexyAdmin\Application\Enums\User\UserBaseFlags;
|
||||
use Koneko\VuexyAdmin\Support\Traits\Migrations\HandlesGeneratedColumns;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
use HandlesGeneratedColumns;
|
||||
|
||||
public function up()
|
||||
{
|
||||
// Añadir columna contenedora si no existe
|
||||
if (!Schema::hasColumn('users', 'flags')) {
|
||||
Schema::table('users', function ($table) {
|
||||
$table->json('flags')
|
||||
->nullable()
|
||||
->after('profile_photo_path')
|
||||
->comment('Dynamic flags storage');
|
||||
});
|
||||
}
|
||||
|
||||
// Añadir columnas generadas
|
||||
$this->addGeneratedColumns('users', UserBaseFlags::cases());
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
// Eliminar columnas generadas
|
||||
$this->dropGeneratedColumns('users', UserBaseFlags::cases());
|
||||
|
||||
// Eliminar columna flags (opcional)
|
||||
Schema::table('users', function ($table) {
|
||||
$table->dropColumnIfExists('flags');
|
||||
});
|
||||
}
|
||||
};
|
@ -1,36 +0,0 @@
|
||||
<?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('user_logins', function (Blueprint $table) {
|
||||
$table->integerIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('user_id')->nullable()->index();
|
||||
$table->ipAddress('ip_address')->nullable();
|
||||
$table->string('user_agent')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('user_id')->references('id')->on('users');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Elimina tablas solo si existen
|
||||
Schema::dropIfExists('user_logins');
|
||||
}
|
||||
};
|
@ -0,0 +1,45 @@
|
||||
<?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('permission_groups', function (Blueprint $table) {
|
||||
$table->smallIncrements('id');
|
||||
|
||||
$table->string("module_register")->index(); // Nombre del módulo registrado
|
||||
$table->unsignedSmallInteger('parent_id')->nullable()->index(); // ID del grupo padre
|
||||
|
||||
$table->string('type', 16)->default('root_group'); // Enum: root_group, sub_group, external_group
|
||||
$table->string("module", 32)->index();
|
||||
$table->string("grupo", 32)->nullable()->index();
|
||||
$table->string("sub_grupo", 32)->nullable()->index();
|
||||
|
||||
$table->json('name')->nullable(); // Nombre i18n
|
||||
$table->json('ui_metadata')->nullable(); // icon, description i18n, flags, ...
|
||||
|
||||
$table->string('priority', 16)->nullable()->index();
|
||||
|
||||
// Auditoría
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('parent_id')->references('id')->on('permission_groups')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('permission_groups');
|
||||
}
|
||||
};
|
@ -27,49 +27,69 @@ return new class extends Migration
|
||||
|
||||
Schema::create($tableNames['permissions'], function (Blueprint $table) {
|
||||
//$table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // permission id
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('group_name')->nullable()->index();
|
||||
$table->string('sub_group_name')->nullable()->index();
|
||||
$table->string('action')->nullable()->index();
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
$table->smallIncrements('id');
|
||||
|
||||
// Permiso Spatie
|
||||
$table->string('name')->unique(); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
|
||||
// Metadata
|
||||
$table->unsignedSmallInteger('group_id')->nullable()->index();
|
||||
$table->json('label')->nullable(); // Nombre del permiso i18n
|
||||
$table->json('ui_metadata')->nullable(); // helperText, floatLabel
|
||||
|
||||
// Acción
|
||||
$table->string('action', 16)->nullable()->index(); // enum PermissionAction: view, create, update, delete, install, clean
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
|
||||
// Auditoría
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['name', 'guard_name']);
|
||||
$table->unique(['group_name', 'sub_group_name', 'action', 'guard_name']);
|
||||
// Relaciones
|
||||
$table->foreign('group_id')
|
||||
->references('id')
|
||||
->on('permission_groups')
|
||||
->restrictOnDelete()
|
||||
->cascadeOnUpdate();
|
||||
});
|
||||
|
||||
Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
|
||||
//$table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // role id
|
||||
$table->smallIncrements('id'); // role id
|
||||
|
||||
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
|
||||
$table->unsignedSmallInteger($columnNames['team_foreign_key'])->nullable();
|
||||
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
|
||||
}
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('style')->nullable();
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->json('ui_metadata')->nullable(); // Tailwind classes, icon, helperText, floatLabel
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
|
||||
// Auditoría
|
||||
$table->timestamps();
|
||||
|
||||
if ($teams || config('permission.testing')) {
|
||||
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
|
||||
|
||||
} else {
|
||||
$table->unique(['name', 'guard_name']);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->unsignedSmallInteger($pivotPermission);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->unsignedSmallInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->unsignedSmallInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
|
||||
|
||||
$table->primary(
|
||||
@ -85,18 +105,19 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
$table->unsignedSmallInteger($pivotRole);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->unsignedSmallInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->unsignedSmallInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
|
||||
|
||||
$table->primary(
|
||||
@ -112,8 +133,8 @@ return new class extends Migration
|
||||
});
|
||||
|
||||
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
$table->unsignedSmallInteger($pivotPermission);
|
||||
$table->unsignedSmallInteger($pivotRole);
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
|
@ -13,16 +13,35 @@ return new class extends Migration
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('settings', function (Blueprint $table) {
|
||||
$table->smallIncrements('id');
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
// Clave del setting
|
||||
$table->string('key')->index();
|
||||
$table->string('key')->index(); // Clave del setting
|
||||
|
||||
// Categoría (opcional pero recomendable)
|
||||
$table->string('category')->nullable()->index();
|
||||
$table->string('namespace', 8)->index(); // Namespace del setting
|
||||
$table->string('environment', 7)->default('prod')->index(); // Entorno de aplicación (prod, dev, test, staging), permite sobrescribir valores según ambiente.
|
||||
$table->string('scope', 6)->default('global')->index(); // Define el alcance: global, tenant, branch, user, etc. Útil en arquitecturas multicliente.
|
||||
|
||||
// Usuario (null para globales)
|
||||
$table->unsignedMediumInteger('user_id')->nullable()->index();
|
||||
$table->string('component', 16)->index(); // Nombre de Componente o proyecto
|
||||
$table->string('module')->nullable()->index(); // composerName de módulo Autocalculado
|
||||
$table->string('group', 16)->index(); // Grupo de configuraciones
|
||||
$table->string('sub_group', 16)->index(); // Sub grupo de configuraciones
|
||||
$table->string('key_name', 24)->index(); // Nombre de la clave de configuraciones
|
||||
$table->unsignedMediumInteger('user_id')->nullable()->index(); // Usuario (null para globales)
|
||||
|
||||
$table->boolean('is_system')->default(false)->index(); // Indica si es un setting de sistema
|
||||
$table->boolean('is_encrypted')->default(false)->index(); // Si el valor está cifrado (para secretos, tokens, passwords).
|
||||
$table->boolean('is_sensitive')->default(false)->index(); // Marca datos sensibles (ej. datos personales, claves API). Puede ocultarse en UI o logs.
|
||||
$table->boolean('is_editable')->default(true)->index(); // Permite o bloquea edición desde la UI (útil para settings de solo lectura).
|
||||
$table->boolean('is_active')->default(true)->index(); // Permite activar/desactivar la aplicación de un setting sin eliminarlo.
|
||||
|
||||
$table->string('encryption_key', 64)->nullable()->index(); // Identificador de la clave usada (ej. 'ssl_cert_2025')
|
||||
$table->string('encryption_algorithm', 16)->nullable(); // Ej. 'AES-256-CBC'
|
||||
$table->timestamp('encryption_rotated_at')->nullable(); // Fecha de última rotación de clave
|
||||
|
||||
$table->string('description')->nullable();
|
||||
$table->string('hint')->nullable();
|
||||
$table->timestamp('last_used_at')->nullable();
|
||||
$table->integer('usage_count')->default(0)->index();
|
||||
|
||||
// Valores segmentados por tipo para mejor rendimiento
|
||||
$table->string('value_string')->nullable();
|
||||
@ -35,28 +54,47 @@ return new class extends Migration
|
||||
$table->string('file_name')->nullable();
|
||||
|
||||
// Auditoría
|
||||
$table->timestamps();
|
||||
$table->unsignedMediumInteger('updated_by')->nullable();
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
// Unique constraint para evitar duplicados
|
||||
$table->unique(['key', 'user_id', 'category']);
|
||||
$table->timestamps();
|
||||
$table->softDeletes(); // THIS ONE
|
||||
|
||||
// Índice de Unicidad Principal (para consultas y updates rápidos)
|
||||
$table->unique(
|
||||
['namespace', 'environment', 'scope', 'component', 'group', 'sub_group', 'key_name', 'user_id'],
|
||||
'uniq_settings_full_context'
|
||||
);
|
||||
|
||||
// Búsqueda rápida por componente
|
||||
$table->index(['namespace', 'component'], 'idx_settings_ns_component');
|
||||
|
||||
// Listar grupos de un componente por scope
|
||||
$table->index(['namespace', 'scope', 'component', 'group'], 'idx_settings_ns_scope_component_group');
|
||||
|
||||
// Listar subgrupos por grupo y componente en un scope
|
||||
$table->index(['namespace', 'scope', 'component', 'group', 'sub_group'], 'idx_settings_ns_scope_component_sg');
|
||||
|
||||
// Consultas por entorno y usuario
|
||||
$table->index(['namespace', 'environment', 'user_id'], 'idx_settings_ns_env_user');
|
||||
|
||||
// Consultas por scope y usuario
|
||||
$table->index(['namespace', 'scope', 'user_id'], 'idx_settings_ns_scope_user');
|
||||
|
||||
// Consultas por estado de actividad o sistema
|
||||
$table->index(['namespace', 'is_active'], 'idx_settings_ns_is_active');
|
||||
$table->index(['namespace', 'is_system'], 'idx_settings_ns_is_system');
|
||||
|
||||
// Consultas por estado de cifrado y usuario
|
||||
$table->index(['namespace', 'is_encrypted', 'user_id'], 'idx_settings_encrypted_user');
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete();
|
||||
$table->foreign('user_id')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('created_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('updated_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('deleted_by')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
|
||||
// Agregar columna virtual unificada
|
||||
DB::statement("ALTER TABLE settings ADD COLUMN value VARCHAR(255) GENERATED ALWAYS AS (
|
||||
CASE
|
||||
WHEN value_string IS NOT NULL THEN value_string
|
||||
WHEN value_integer IS NOT NULL THEN CAST(value_integer AS CHAR)
|
||||
WHEN value_boolean IS NOT NULL THEN IF(value_boolean, 'true', 'false')
|
||||
WHEN value_float IS NOT NULL THEN CAST(value_float AS CHAR)
|
||||
WHEN value_text IS NOT NULL THEN LEFT(value_text, 255)
|
||||
WHEN value_binary IS NOT NULL THEN '[binary_data]'
|
||||
ELSE NULL
|
||||
END
|
||||
) VIRTUAL");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::connection('vault')->create('vault_keys', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
|
||||
// Contexto de clave
|
||||
$table->string('alias', 64)->unique()->index();
|
||||
$table->string('owner_project', 64)->index();
|
||||
$table->string('environment', 10)->default('prod')->index(); // prod, dev, staging
|
||||
$table->string('namespace', 32)->default('core')->index();
|
||||
$table->string('scope', 16)->default('global')->index(); // global, tenant, user
|
||||
|
||||
// Datos de la clave
|
||||
$table->string('algorithm', 32)->default('AES-256-CBC');
|
||||
$table->binary('key_material');
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->boolean('is_sensitive')->default(true);
|
||||
|
||||
// Control de rotación
|
||||
$table->timestamp('rotated_at')->nullable();
|
||||
$table->unsignedInteger('rotation_count')->default(0);
|
||||
|
||||
// Auditoría
|
||||
$table->unsignedBigInteger('created_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Índices adicionales
|
||||
$table->index(['owner_project', 'environment', 'namespace', 'scope', 'is_active'], 'idx_full_context');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::connection('vault')->dropIfExists('settings');
|
||||
}
|
||||
|
||||
};
|
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('external_apis', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
// Identidad y relación
|
||||
$table->string('slug')->unique(); // api-google-analytics
|
||||
$table->string('name'); // Google Analytics
|
||||
$table->string('module')->index(); // vuexy-website-admin
|
||||
$table->string('provider')->nullable()->index(); // Google, Twitter, Banxico
|
||||
|
||||
// Autenticación y alcance
|
||||
$table->string('auth_type', 16)->nullable()->index(); // api_key, oauth2, jwt, none
|
||||
$table->json('credentials')->nullable(); // api_key, secret, token, etc.
|
||||
$table->json('scopes')->nullable(); // ['read', 'write', 'analytics']
|
||||
|
||||
// Conectividad
|
||||
$table->string('base_url')->nullable(); // https://api.example.com
|
||||
$table->string('doc_url')->nullable(); // https://docs.example.com
|
||||
|
||||
// Estado y entorno
|
||||
$table->string('environment')->default('production')->index(); // dev, staging, prod
|
||||
$table->boolean('is_active')->default(true)->index(); // toggle global
|
||||
|
||||
// Extensión dinámica
|
||||
$table->json('metadata')->nullable(); // libre: headers extra, tags, categorías
|
||||
$table->json('config')->nullable(); // libre: UI params, rate limits, etc.
|
||||
|
||||
// Auditoría
|
||||
$table->timestamps();
|
||||
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('updated_by')->nullable()->index();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('created_by')->references('id')->on('users')->nullOnDelete();
|
||||
$table->foreign('updated_by')->references('id')->on('users')->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('external_apis');
|
||||
}
|
||||
};
|
@ -0,0 +1,58 @@
|
||||
<?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('user_logins', function (Blueprint $table) {
|
||||
$table->integerIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('user_id')->nullable()->index();
|
||||
|
||||
$table->ipAddress('ip_address')->nullable()->index();
|
||||
$table->string('user_agent')->nullable();
|
||||
$table->string('device_type')->nullable();
|
||||
$table->string('browser')->nullable();
|
||||
$table->string('browser_version')->nullable();
|
||||
$table->string('os')->nullable();
|
||||
$table->string('os_version')->nullable();
|
||||
$table->string('country')->nullable()->index();
|
||||
$table->string('region')->nullable();
|
||||
$table->string('city')->nullable();
|
||||
$table->decimal('lat', 10, 8)->nullable();
|
||||
$table->decimal('lng', 11, 8)->nullable();
|
||||
$table->boolean('is_proxy')->default(false)->index();
|
||||
$table->boolean('login_success')->default(true)->index();
|
||||
$table->timestamp('logout_at')->nullable();
|
||||
$table->string('logout_reason')->nullable();
|
||||
$table->json('additional_info')->nullable();
|
||||
|
||||
// Auditoría
|
||||
$table->timestamps();
|
||||
|
||||
// Indices
|
||||
$table->index(['user_id', 'login_success']);
|
||||
$table->index(['user_id', 'logout_at']);
|
||||
$table->index(['user_id', 'logout_at', 'login_success']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('user_id')->references('id')->on('users');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Elimina tablas solo si existen
|
||||
Schema::dropIfExists('user_logins');
|
||||
}
|
||||
};
|
@ -0,0 +1,73 @@
|
||||
<?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('security_events', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
|
||||
$table->string('module')->nullable()->index(); // Modulo (opcional pero recomendable)
|
||||
$table->unsignedMediumInteger('user_id')->nullable()->index(); // Usuario
|
||||
|
||||
// Información básica del evento
|
||||
$table->string('event_type')->index();
|
||||
$table->string('status')->default('new')->index();
|
||||
|
||||
// Información de acceso
|
||||
$table->ipAddress('ip_address')->nullable()->index();
|
||||
$table->string('user_agent')->nullable();
|
||||
$table->string('device_type', 100)->nullable();
|
||||
$table->string('browser', 100)->nullable();
|
||||
$table->string('browser_version')->nullable();
|
||||
$table->string('os', 100)->nullable();
|
||||
$table->string('os_version', 100)->nullable();
|
||||
|
||||
// Información GeoIP (geoip2)
|
||||
$table->string('country')->nullable()->index();
|
||||
$table->string('region')->nullable();
|
||||
$table->string('city')->nullable();
|
||||
$table->decimal('lat', 10, 8)->nullable();
|
||||
$table->decimal('lng', 11, 8)->nullable();
|
||||
|
||||
// Información adicional del evento
|
||||
$table->boolean('is_proxy')->default(false)->index();
|
||||
$table->string('url')->nullable();
|
||||
$table->string('http_method', 10)->nullable();
|
||||
|
||||
// JSON payload del evento para análisis avanzado
|
||||
$table->json('payload')->nullable();
|
||||
|
||||
// Auditoría
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Indices
|
||||
$table->index(['event_type', 'status', 'user_id']);
|
||||
$table->index(['user_id', 'event_type']);
|
||||
$table->index(['user_id', 'event_type', 'status']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
|
||||
$table->foreign('deleted_by')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Elimina tablas solo si existen
|
||||
Schema::dropIfExists('user_logins');
|
||||
}
|
||||
};
|
@ -0,0 +1,61 @@
|
||||
<?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('system_logs', function (Blueprint $table) {
|
||||
$table->integerIncrements('id');
|
||||
|
||||
// Relación polimórfica: puede ser un pedido, una factura, etc.
|
||||
$table->unsignedMediumInteger('loggable_id')->index();
|
||||
$table->string('loggable_type')->index();
|
||||
|
||||
$table->string('module')->nullable()->index(); // Modulo (opcional pero recomendable)
|
||||
$table->unsignedMediumInteger('user_id')->nullable()->index(); // Usuario
|
||||
|
||||
$table->string('level', 16)->index(); // info, warning, error
|
||||
$table->text('message');
|
||||
$table->json('context')->nullable(); // datos estructurados
|
||||
|
||||
$table->string('trigger_type', 16)->index(); // user, cronjob, webhook, etc.
|
||||
$table->unsignedMediumInteger('trigger_id')->nullable()->index(); // user_id, job_id, etc.
|
||||
|
||||
// Auditoría
|
||||
$table->unsignedMediumInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Índices
|
||||
$table->index(['loggable_id', 'loggable_type']);
|
||||
$table->index(['loggable_type', 'user_id']);
|
||||
$table->index(['loggable_type', 'level']);
|
||||
$table->index(['trigger_type', 'level']);
|
||||
$table->index(['loggable_type', 'user_id', 'level']);
|
||||
$table->index(['trigger_type', 'user_id', 'level']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('restrict');
|
||||
$table->foreign('updated_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('deleted_by')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Elimina tablas solo si existen
|
||||
Schema::dropIfExists('system_logs');
|
||||
}
|
||||
};
|
@ -0,0 +1,72 @@
|
||||
<?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('user_interactions', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
|
||||
$table->string('module')->nullable()->index(); // Modulo (opcional pero recomendable)
|
||||
$table->unsignedMediumInteger('user_id')->index(); // Usuario
|
||||
|
||||
$table->string('livewire_component')->nullable()->index(); // ejemplo: inventory.products
|
||||
$table->string('action')->index(); // ejemplo: view, update, export
|
||||
$table->string('security_level')->default('normal')->index(); // normal, sensible, crítico
|
||||
|
||||
$table->ipAddress('ip_address')->nullable();
|
||||
$table->string('user_agent')->nullable();
|
||||
$table->json('context')->nullable();
|
||||
|
||||
// 🛡️ Flags de auditoría administrativa
|
||||
$table->json('user_flags')->nullable(); // snapshot de is_admin, is_client, etc.
|
||||
$table->json('user_roles')->nullable(); // ["admin", "manager"]
|
||||
|
||||
$table->mediumText('notes')->nullable(); // comentarios internos de admin
|
||||
$table->json('chat_thread')->nullable(); // [{user_id:1, msg:"...", at:"..."}, ...]
|
||||
|
||||
$table->boolean('is_reviewed')->default(false)->index();
|
||||
$table->boolean('is_flagged')->default(false)->index();
|
||||
$table->boolean('is_escalated')->default(false)->index();
|
||||
$table->unsignedMediumInteger('reviewed_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('flagged_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('escalated_by')->nullable()->index();
|
||||
|
||||
// Auditoria
|
||||
$table->unsignedMediumInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Indices
|
||||
$table->index(['user_id', 'is_reviewed', 'security_level']);
|
||||
$table->index(['user_id', 'is_flagged', 'security_level']);
|
||||
$table->index(['user_id', 'is_escalated', 'security_level']);
|
||||
$table->index(['user_id', 'is_reviewed', 'is_flagged', 'is_escalated', 'security_level'])->name('user_interactions_user_id_is_reviewed_flagged_escalated_sec_lev_index');
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('restrict');
|
||||
$table->foreign('reviewed_by')->references('id')->on('users')->onDelete('restrict');
|
||||
$table->foreign('flagged_by')->references('id')->on('users')->onDelete('restrict');
|
||||
$table->foreign('escalated_by')->references('id')->on('users')->onDelete('restrict');
|
||||
$table->foreign('updated_by')->references('id')->on('users')->onDelete('restrict');
|
||||
$table->foreign('deleted_by')->references('id')->on('users')->onDelete('restrict');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_interactions');
|
||||
}
|
||||
};
|
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('device_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->unsignedMediumInteger('user_id')->nullable()->index();
|
||||
$table->string('token')->unique(); // Token del dispositivo
|
||||
$table->string('platform', 32)->nullable()->index(); // Plataforma: ios, android, web, desktop, etc.
|
||||
$table->string('client')->nullable(); // Navegador o cliente usado
|
||||
$table->mediumText('device_info')->nullable(); // Información extendida del dispositivo
|
||||
$table->string('location', 128)->nullable(); // Ubicación del dispositivo (opcional)
|
||||
$table->timestamp('last_used_at')->nullable(); // Último uso
|
||||
|
||||
$table->boolean('is_active')->default(true);
|
||||
|
||||
// Auditoria
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Indices
|
||||
$table->index(['user_id', 'platform']);
|
||||
$table->index(['user_id', 'is_active']);
|
||||
$table->index(['user_id', 'is_active', 'platform']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('user_id')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('created_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('updated_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('deleted_by')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('device_tokens');
|
||||
}
|
||||
};
|
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('system_notifications', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->string('scope', 16)->default('both')->index(); // enum 'admin', 'frontend', 'both'
|
||||
$table->string('type', 16)->default('info')->index(); // enum 'info', 'success', 'warning', 'danger', 'promo'
|
||||
|
||||
$table->string('title')->index();
|
||||
$table->text('message');
|
||||
|
||||
$table->string('channel', 32)->default('toast')->index(); // toast | push | websocket | etc.
|
||||
|
||||
$table->string('style', 16)->default('banner')->index(); // enum 'toast', 'banner', 'modal', 'inline'
|
||||
$table->string('priority', 16)->default('medium')->index(); // Enum 'low', 'medium', 'high', 'critical'
|
||||
|
||||
$table->boolean('requires_confirmation')->default(false)->index();
|
||||
|
||||
$table->string('target_area', 32)->nullable()->comment('Ej: header, sidebar, checkout, etc.')->index();
|
||||
$table->json('tags')->nullable();
|
||||
$table->json('roles')->nullable();
|
||||
$table->json('user_flags')->nullable();
|
||||
|
||||
$table->boolean('is_active')->default(true)->index();
|
||||
$table->timestamp('starts_at')->nullable();
|
||||
$table->timestamp('ends_at')->nullable();
|
||||
|
||||
// Auditoría
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Indices
|
||||
$table->index(['scope', 'type']);
|
||||
$table->index(['is_active', 'starts_at', 'ends_at']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('created_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('updated_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('deleted_by')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('system_notifications');
|
||||
}
|
||||
};
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('system_notification_user', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->unsignedMediumInteger('system_notification_id')->index();
|
||||
$table->unsignedMediumInteger('user_id')->index();
|
||||
|
||||
$table->string('channel', 32)->default('toast')->index(); // toast | push | websocket | etc.
|
||||
|
||||
$table->boolean('is_read')->default(false)->index();
|
||||
$table->timestamp('read_at')->nullable()->index();
|
||||
|
||||
$table->boolean('is_dismissed')->default(false)->index();
|
||||
$table->timestamp('dismissed_at')->nullable()->index();
|
||||
|
||||
$table->boolean('is_confirmed')->default(false)->comment('Confirmación explícita si se requiere')->index();
|
||||
$table->timestamp('confirmed_at')->nullable()->index();
|
||||
$table->text('confirmation_notes')->nullable();
|
||||
|
||||
// Auditoria
|
||||
$table->timestamps();
|
||||
|
||||
// Indices
|
||||
$table->unique(['system_notification_id', 'user_id']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('system_notification_id')->references('id')->on('system_notifications')->cascadeOnDelete();
|
||||
$table->foreign('user_id')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('system_notification_user');
|
||||
}
|
||||
};
|
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->string('module')->nullable()->index(); // Modulo (opcional pero recomendable)
|
||||
$table->unsignedMediumInteger('user_id')->index(); // Usuario
|
||||
|
||||
$table->string('channel', 32)->default('toast')->index(); // toast | push | websocket | etc.
|
||||
|
||||
$table->string('type', 16)->default('info')->index(); // Enum: info, success, danger, warning, system
|
||||
$table->string('title')->index();
|
||||
$table->text('body')->nullable();
|
||||
$table->json('data')->nullable();
|
||||
$table->string('action_url')->nullable();
|
||||
|
||||
$table->boolean('is_read')->default(false)->index();
|
||||
$table->timestamp('read_at')->nullable();
|
||||
|
||||
// Auditoria
|
||||
$table->timestamps();
|
||||
$table->boolean('is_dismissed')->default(false)->index();
|
||||
$table->boolean('is_deleted')->default(false)->index();
|
||||
$table->unsignedMediumInteger('emitted_by')->nullable()->index();
|
||||
|
||||
$table->softDeletes();
|
||||
|
||||
// Indices
|
||||
$table->index(['type', 'title']);
|
||||
$table->index(['is_read', 'user_id']);
|
||||
$table->index(['user_id', 'is_read', 'is_deleted']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('user_id')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('emitted_by')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('notifications');
|
||||
}
|
||||
};
|
@ -0,0 +1,66 @@
|
||||
<?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('module_packages', function (Blueprint $table) {
|
||||
$table->smallIncrements('id');
|
||||
|
||||
$table->string('name')->unique();
|
||||
$table->string('display_name');
|
||||
$table->text('description')->nullable();
|
||||
$table->jsonb('keywords')->nullable();
|
||||
|
||||
$table->string('author_name')->nullable();
|
||||
$table->string('author_email')->nullable();
|
||||
|
||||
$table->string('source_url', 500)->nullable();
|
||||
$table->string('composer_url', 500)->nullable();
|
||||
|
||||
$table->string('cover_image', 500)->nullable();
|
||||
$table->string('readme_path', 500)->nullable();
|
||||
|
||||
$table->string('source_type', 16)->default(false); // Enum
|
||||
$table->boolean('zip_available')->default(false);
|
||||
|
||||
$table->json('composer')->nullable(); // dump completo del composer.json
|
||||
|
||||
$table->string('repository_type', 16)->default('public')->index();
|
||||
$table->boolean('active')->default(true);
|
||||
|
||||
// Auditoría
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Indices
|
||||
$table->index(['name', 'display_name']);
|
||||
$table->index(['repository_type', 'active']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('created_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('updated_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('deleted_by')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Elimina tablas solo si existen
|
||||
Schema::dropIfExists('module_packages');
|
||||
}
|
||||
};
|
@ -0,0 +1,54 @@
|
||||
<?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('installed_modules', function (Blueprint $table) {
|
||||
$table->smallIncrements('id');
|
||||
|
||||
$table->unsignedSmallInteger('module_package_id')->index(); // Relación con module_packages
|
||||
$table->string('slug')->unique(); // Ej: vuexy-website-admin
|
||||
$table->string('name'); // Ej: koneko/laravel-vuexy-website-admin
|
||||
$table->string('version')->nullable(); // Versión instalada
|
||||
$table->string('install_path')->nullable(); // Path en vendor/ o custom
|
||||
$table->boolean('enabled')->default(true); // Activado para el sistema
|
||||
|
||||
// Control
|
||||
$table->json('install_options')->nullable(); // flags de instalación zip, git, etc.
|
||||
|
||||
// Auditoría y estado
|
||||
$table->timestamp('installed_at')->nullable();
|
||||
$table->timestamp('last_checked_at')->nullable(); // Sincronización con fuente
|
||||
|
||||
// Auditoría
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Indices
|
||||
$table->index(['module_package_id', 'enabled']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('module_package_id')->references('id')->on('module_packages')->onDelete('cascade');
|
||||
$table->foreign('created_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('updated_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('deleted_by')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('installed_modules');
|
||||
}
|
||||
};
|
@ -0,0 +1,57 @@
|
||||
<?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('vuexy_modules', function (Blueprint $table) {
|
||||
$table->string('slug')->primary(); // Ej. koneko-vuexy-contacts
|
||||
$table->string('name'); // Nombre completo del módulo
|
||||
$table->string('vendor')->nullable(); // koneko-st, vendor de composer
|
||||
|
||||
$table->unsignedSmallInteger('installed_module_id')->nullable()->index();
|
||||
$table->string('version')->nullable(); // 1.0.0
|
||||
$table->string('build_version')->nullable(); // 20250429223531
|
||||
$table->string('type')->default('plugin'); // core, plugin, theme, etc.
|
||||
$table->string('provider')->nullable();
|
||||
$table->json('tags')->nullable();
|
||||
$table->json('metadata')->nullable(); // json libre para UI, etc.
|
||||
|
||||
// Auditoria
|
||||
$table->boolean('is_enabled')->default(true)->index(); // Para activar/desactivar
|
||||
$table->boolean('is_installed')->default(false)->index(); // Para trackear instalación
|
||||
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// Indices
|
||||
$table->index(['is_enabled', 'is_installed']);
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('installed_module_id')->references('id')->on('installed_modules')->onDelete('set null');
|
||||
$table->foreign('created_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('updated_by')->references('id')->on('users')->restrictOnDelete();
|
||||
$table->foreign('deleted_by')->references('id')->on('users')->restrictOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Elimina tablas solo si existen
|
||||
Schema::dropIfExists('vuexy_modules');
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user