Configuración Dinámica Key-Value
Mañuti implementa un almacén global de configuraciones (System Configuration Store) que permite a los operadores del sistema alterar umbrales de seguridad, políticas operativas y branding en caliente sin reiniciar servicios ni modificar variables de entorno .env.
1. Esquema de Datos y Tipado Estricto
La tabla configuracion_sistema almacena los parámetros serializados junto con metadatos de categoría y tipado:
CREATE TABLE `configuracion_sistema` (
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`categoria` VARCHAR(255) DEFAULT 'General',
`clave` VARCHAR(255) NOT NULL UNIQUE,
`valor` TEXT NOT NULL,
`descripcion` VARCHAR(255) NULL,
`tipo_dato` VARCHAR(50) DEFAULT 'string',
`created_at` TIMESTAMP NULL,
`updated_at` TIMESTAMP NULL
);
Tipos de Datos Soportados
string: Texto plano o rutas (e.g.,system_app_name,system_logo_url).number: Enteros casteados en tiempo de ejecución (e.g.,login_max_attempts,security_idle_timeout).boolean: Banderas binarias (true/false) renderizadas como switches interactivos en la interfaz administrativa.array: Listas JSON deserializadas a arreglos nativos de PHP (e.g.,security_pii_fields).
2. Caché Persistente en Redis y Método Helper
Para evitar que una consulta SQL golpee MariaDB en cada petición HTTP, el modelo ConfiguracionSistema almacena cada parámetro en la RAM de Redis:
// app/Models/ConfiguracionSistema.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
class ConfiguracionSistema extends Model
{
protected $table = 'configuracion_sistema';
protected $fillable = ['categoria', 'clave', 'valor', 'descripcion', 'tipo_dato'];
public static function getValor(string $clave, mixed $default = null): mixed
{
return Cache::remember("sys_config_{$clave}", 3600, function () use ($clave, $default) {
$config = self::where('clave', $clave)->first();
if (!$config) return $default;
return match ($config->tipo_dato) {
'boolean' => filter_var($config->valor, FILTER_VALIDATE_BOOLEAN),
'number' => (int) $config->valor,
'array' => json_decode($config->valor, true) ?? [],
default => $config->valor,
};
});
}
}
3. Modo Mantenimiento Inteligente (CheckSystemMaintenance)
A diferencia del comando artisan down (que bloquea todo el tráfico a nivel de servidor web), Mañuti cuenta con un middleware dinámico gobernado por la clave system_maintenance_mode:
// app/Http/Middleware/CheckSystemMaintenance.php
public function handle(Request $request, Closure $next)
{
$isMaintenance = ConfiguracionSistema::getValor('system_maintenance_mode', false);
if ($isMaintenance) {
// Excepción de bypass: El Super Admin puede ingresar y realizar pruebas
if (Auth::check() && Auth::user()->hasRole('Super Admin')) {
return $next($request);
}
// Permite acceso a rutas de autenticación para administradores
if ($request->is('login') || $request->is('logout')) {
return $next($request);
}
abort(503, 'Plataforma en mantenimiento programado. Intente más tarde.');
}
return $next($request);
}
4. Inyección Global en Vistas (View::share)
Para que el título, favicons y directivas SEO estén disponibles en todas las plantillas Blade sin consultarlas manualmente en los controladores, el AppServiceProvider precarga la colección:
// app/Providers/AppServiceProvider.php
if (Schema::hasTable('configuracion_sistema')) {
$globalConfig = Cache::remember('global_site_config', 3600, function () {
return ConfiguracionSistema::all()->pluck('valor', 'clave')->toArray();
});
View::share('config', $globalConfig);
}