Testing Alpha

This commit is contained in:
2025-05-11 14:14:50 -06:00
parent 988b86a33d
commit a7002701f5
1903 changed files with 77534 additions and 36485 deletions

View File

@ -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']);
});
}
};

View File

@ -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');
});
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

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

View File

@ -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");
}
/**

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};

View File

@ -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');
}
};