Prepare Beta Version
This commit is contained in:
@ -0,0 +1,78 @@
|
||||
<?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
|
||||
{
|
||||
$keyVault = config_m()->setGroup('key_vault');
|
||||
|
||||
$mode = $keyVault->get('mode', 'client');
|
||||
$driver = $keyVault->get('client.driver', 'database');
|
||||
$table = $keyVault->get('server.table', 'vault_keys');
|
||||
$conn = $keyVault->get('server.connection', 'vault');
|
||||
|
||||
$isServer = in_array($mode, ['server', 'both']);
|
||||
$isDatabaseDriver = $driver === 'database';
|
||||
|
||||
if (!$isServer) {
|
||||
echo "\n ⏩ Skipping: vault_keys not needed for mode '{$mode}'.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$isDatabaseDriver) {
|
||||
echo "\n ⏩ Skipping: vault_keys not needed for driver '{$driver}'.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (Schema::connection($conn)->hasTable($table)) {
|
||||
echo "\n ⏩ Table {$table} already exists on connection '{$conn}'.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Crear la tabla
|
||||
Schema::connection($conn)->create($table, function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
|
||||
$table->string('alias', 64)->unique()->index();
|
||||
$table->string('owner_project', 64)->index();
|
||||
$table->string('namespace', 32)->default('core')->index();
|
||||
|
||||
$table->string('algorithm', 32)->default('AES-256-CBC');
|
||||
$table->binary('key_material');
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->boolean('is_sensitive')->default(true);
|
||||
|
||||
$table->timestamp('rotated_at')->nullable();
|
||||
$table->unsignedInteger('rotation_count')->default(0);
|
||||
|
||||
$table->unsignedBigInteger('created_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('updated_by')->nullable()->index();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['owner_project', 'namespace', 'is_active'], 'idx_full_context');
|
||||
});
|
||||
|
||||
info("✅ Created table `{$table}` in connection [{$conn}].");
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$keyVault = config_m()->setGroup('key_vault');
|
||||
|
||||
$driver = $keyVault->get('client.driver', 'database');
|
||||
$table = $keyVault->get('server.table', 'vault_keys');
|
||||
$conn = $keyVault->get('server.connection', 'vault');
|
||||
|
||||
if ($driver === 'database' && Schema::connection($conn)->hasTable($table)) {
|
||||
Schema::connection($conn)->dropIfExists($table);
|
||||
info("🗑️ Dropped table `{$table}` from connection [{$conn}].");
|
||||
}
|
||||
}
|
||||
};
|
@ -1,57 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyAdmin\Database\Migrations;
|
||||
|
||||
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.
|
||||
*/
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('settings', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
$table->integerIncrements('id');
|
||||
|
||||
$table->string('key')->index(); // Clave del setting
|
||||
// Clave identificadora única para uso directo en Redis u otras estructuras rápidas
|
||||
$table->string('key')->unique();
|
||||
|
||||
$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.
|
||||
// Contexto completo del setting
|
||||
$table->string('namespace', 8)->index(); // Ej. 'koneko'
|
||||
$table->string('environment', 7)->default('prod')->index(); // prod, dev, staging, test
|
||||
$table->string('component', 16)->index(); // Ej. 'vuexy-admin'
|
||||
$table->string('module')->nullable()->index(); // composerName del módulo
|
||||
|
||||
$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->string('scope', 16)->nullable()->index(); // user, branch, tenant, etc.
|
||||
$table->unsignedMediumInteger('scope_id')->nullable()->index(); // ID vinculado al scope (ej. user_id, branch_id)
|
||||
|
||||
$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('group', 16)->index(); // Grupo funcional (ej. layout, ui, behavior)
|
||||
$table->string('section', 16)->default('default')->index(); // Bloque intermedio semántico
|
||||
$table->string('sub_group', 16)->default('default')->index(); // Subgrupo semántico opcional
|
||||
$table->string('key_name', 24)->index(); // Sub-subgrupo lógico o tipo de configuración
|
||||
|
||||
$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
|
||||
// Flags operativos
|
||||
$table->boolean('is_system')->default(false)->index();
|
||||
$table->boolean('is_sensitive')->default(false)->index();
|
||||
$table->boolean('is_file')->default(false)->index();
|
||||
$table->boolean('is_encrypted')->default(false)->index();
|
||||
$table->boolean('is_config')->default(false)->index();
|
||||
$table->boolean('is_editable')->default(true)->index();
|
||||
$table->boolean('is_track_usage')->default(false)->index();
|
||||
$table->boolean('is_should_cache')->default(true)->index();
|
||||
$table->boolean('is_active')->default(true)->index();
|
||||
|
||||
// Metadata para archivos y cifrado
|
||||
$table->string('mime_type', 50)->nullable();
|
||||
$table->string('file_name')->nullable();
|
||||
$table->string('encryption_algorithm', 16)->nullable();
|
||||
$table->string('encryption_key', 64)->nullable()->index();
|
||||
$table->timestamp('encryption_rotated_at')->nullable();
|
||||
|
||||
// Expiración del setting o su valor cacheado
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->unsignedInteger('usage_count')->nullable();
|
||||
$table->timestamp('last_used_at')->nullable();
|
||||
$table->unsignedSmallInteger('cache_ttl')->nullable();
|
||||
$table->timestamp('cache_expires_at')->nullable();
|
||||
|
||||
// Descripciones para UI
|
||||
$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
|
||||
// Valores segmentados
|
||||
$table->string('value_string')->nullable();
|
||||
$table->integer('value_integer')->nullable();
|
||||
$table->boolean('value_boolean')->nullable();
|
||||
$table->float('value_float', 16, 8)->nullable();
|
||||
$table->text('value_text')->nullable();
|
||||
$table->binary('value_binary')->nullable();
|
||||
$table->string('mime_type', 50)->nullable();
|
||||
$table->string('file_name')->nullable();
|
||||
|
||||
// Auditoría
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index();
|
||||
@ -59,50 +72,43 @@ return new class extends Migration
|
||||
$table->unsignedMediumInteger('deleted_by')->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes(); // THIS ONE
|
||||
$table->softDeletes();
|
||||
|
||||
// Í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'
|
||||
);
|
||||
// 📌 Clave única por contexto semántico-lógico
|
||||
$table->unique([
|
||||
'namespace',
|
||||
'environment',
|
||||
'component',
|
||||
'scope',
|
||||
'scope_id',
|
||||
'group',
|
||||
'section',
|
||||
'sub_group',
|
||||
'key_name'
|
||||
], 'uniq_settings_full_context');
|
||||
|
||||
// Búsqueda rápida por componente
|
||||
$table->index(['namespace', 'component'], 'idx_settings_ns_component');
|
||||
// 📈 Índices especializados para consultas
|
||||
$table->index(['namespace', 'environment', 'component'], 'idx_ns_env_component');
|
||||
$table->index(['namespace', 'environment', 'component', 'is_active'], 'idx_ns_is_active');
|
||||
$table->index(['namespace', 'environment', 'component', 'is_system'], 'idx_ns_is_system');
|
||||
$table->index(['namespace', 'environment', 'component', 'is_config'], 'idx_ns_is_config');
|
||||
$table->index(['namespace', 'environment', 'component', 'is_encrypted'], 'idx_ns_is_encrypted');
|
||||
$table->index(['namespace', 'environment', 'component', 'is_file'], 'idx_ns_is_file');
|
||||
$table->index(['namespace', 'environment', 'component', 'is_editable'], 'idx_ns_is_editable');
|
||||
$table->index(['namespace', 'environment', 'component', 'is_track_usage'], 'idx_ns_is_track_usage');
|
||||
$table->index(['namespace', 'environment', 'component', 'is_should_cache'], 'idx_ns_is_should_cache');
|
||||
$table->index(['namespace', 'environment', 'component', 'group', 'section', 'sub_group'], 'idx_ns_env_comp_group_sect_subg');
|
||||
$table->index(['namespace', 'environment', 'component', 'group', 'section', 'sub_group', 'scope', 'scope_id'], 'idx_ns_env_comp_group_sect_subg_scope');
|
||||
|
||||
// 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')->restrictOnDelete();
|
||||
// 🔒 Relaciones de auditoría
|
||||
$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('settings');
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -1,56 +0,0 @@
|
||||
<?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');
|
||||
}
|
||||
|
||||
};
|
Reference in New Issue
Block a user