chore: setup core configurations and bootstrap
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ============================================================
|
||||
* @project biiproject
|
||||
* @author Andika Debi Putra
|
||||
* @email andikadebiputra@gmail.com
|
||||
* @website https://biiproject.com
|
||||
* @copyright Copyright (c) 2026 Andika Debi Putra
|
||||
* @license Proprietary - All Rights Reserved
|
||||
* @version 1.0.0
|
||||
* @created 2026-05-01
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
use Spatie\Permission\Middleware\RoleMiddleware;
|
||||
use Spatie\Permission\Middleware\PermissionMiddleware;
|
||||
use Spatie\Permission\Middleware\RoleOrPermissionMiddleware;
|
||||
use App\Http\Middleware\CheckActivePermission;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
channels: __DIR__.'/../routes/channels.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
// GLOBAL MIDDLEWARE
|
||||
$middleware->append(\App\Http\Middleware\GzipCompression::class);
|
||||
|
||||
// REGISTER ALIAS MIDDLEWARE
|
||||
$middleware->alias([
|
||||
'role' => RoleMiddleware::class,
|
||||
'permission' => PermissionMiddleware::class,
|
||||
'role_or_permission' => RoleOrPermissionMiddleware::class,
|
||||
|
||||
// CUSTOM MIDDLEWARE (CEK PERMISSION AKTIF)
|
||||
'active-permission' => CheckActivePermission::class,
|
||||
'password-expiry' => \App\Http\Middleware\PasswordExpiryMiddleware::class,
|
||||
'check-legal' => \App\Http\Middleware\CheckLegalAgreement::class,
|
||||
'mobile-guard' => \App\Http\Middleware\MobileMaintenanceMiddleware::class,
|
||||
'tab-permission' => \App\Http\Middleware\CheckTabPermission::class,
|
||||
'menu-permission' => \App\Http\Middleware\CheckMenuPermission::class,
|
||||
]);
|
||||
|
||||
$middleware->web(append: [
|
||||
\App\Http\Middleware\SecurityHeaders::class,
|
||||
\App\Http\Middleware\IpAccessControl::class,
|
||||
'password-expiry',
|
||||
'check-legal',
|
||||
]);
|
||||
|
||||
})
|
||||
->withSchedule(function (\Illuminate\Console\Scheduling\Schedule $schedule): void {
|
||||
// Dikelola di routes/console.php
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
$exceptions->report(function (\Throwable $e) {
|
||||
// --- AI SELF HEALING INTERCEPTOR ---
|
||||
if (!($e instanceof \Symfony\Component\HttpKernel\Exception\HttpException)) {
|
||||
try {
|
||||
// Re-entrancy guard: if the AI healer itself is currently running,
|
||||
// never re-enter (prevents infinite loops if healing trips an error).
|
||||
if (defined('AI_HEALER_RUNNING')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$isAiHealingEnabled = false;
|
||||
$isAiProviderEnabled = false;
|
||||
try {
|
||||
$isAiHealingEnabled = app(\App\Services\SystemConfig\SystemConfigService::class)
|
||||
->get('ai_healing_enabled', false);
|
||||
$isAiProviderEnabled = app(\App\Services\SystemConfig\SystemConfigService::class)
|
||||
->get('ai_enabled', false);
|
||||
} catch (\Throwable $t) {}
|
||||
|
||||
if (!$isAiHealingEnabled || !$isAiProviderEnabled) {
|
||||
// Healer or Provider disabled — fall through to Sentry below.
|
||||
} else {
|
||||
// Skip exceptions originating *from* the healing pipeline itself
|
||||
// OR from critical files we never want the healer to touch.
|
||||
$traceStr = $e->getFile() . $e->getTraceAsString();
|
||||
$msg = (string) $e->getMessage();
|
||||
$isInternalHealerError = str_contains($traceStr, 'AiHealerJob')
|
||||
|| str_contains($traceStr, 'AiHealingLog')
|
||||
|| str_contains($traceStr, 'AiSelfHealingController')
|
||||
|| str_contains($traceStr, 'app/Services/AI/')
|
||||
// Self-exclusion: never let the healer try to edit these files.
|
||||
|| str_contains($msg, 'ai-self-healing.blade.php')
|
||||
|| str_contains($msg, 'navigation.blade.php')
|
||||
|| str_contains($msg, 'layouts/app.blade.php')
|
||||
|| str_contains($traceStr, 'ai-self-healing.blade.php')
|
||||
|| str_contains($traceStr, 'navigation.blade.php');
|
||||
|
||||
if (!$isInternalHealerError) {
|
||||
// Dedup: same error_type already pending OR diagnosing.
|
||||
// Diagnosing logs older than 5 min are considered stuck and reset to pending.
|
||||
\App\Models\AiHealingLog::where('error_type', get_class($e))
|
||||
->where('status', 'diagnosing')
|
||||
->where('updated_at', '<', now()->subMinutes(5))
|
||||
->update(['status' => 'pending', 'action_taken' => 'Auto-reset from stuck diagnosing state']);
|
||||
|
||||
$duplicate = \App\Models\AiHealingLog::where('error_type', get_class($e))
|
||||
->whereIn('status', ['pending', 'diagnosing'])
|
||||
->where('created_at', '>=', now()->subMinutes(2))
|
||||
->exists();
|
||||
|
||||
if (!$duplicate) {
|
||||
// --- CIRCUIT BREAKER ---
|
||||
$maxPerHour = (int) app(\App\Services\SystemConfig\SystemConfigService::class)
|
||||
->get('ai_healing_max_attempts_per_hour', 5);
|
||||
|
||||
$recentCount = \App\Models\AiHealingLog::where('created_at', '>', now()->subHour())
|
||||
->whereIn('status', ['resolved', 'pending', 'diagnosing'])
|
||||
->count();
|
||||
|
||||
if ($recentCount >= $maxPerHour) {
|
||||
// Circuit breaker tripped! Only log to standard Laravel log, don't trigger AI.
|
||||
\Illuminate\Support\Facades\Log::warning("AI Healer Circuit Breaker tripped. Total fixes in last hour: {$recentCount}. Threshold: {$maxPerHour}");
|
||||
return;
|
||||
}
|
||||
|
||||
define('AI_HEALER_RUNNING', true);
|
||||
|
||||
$log = \App\Models\AiHealingLog::create([
|
||||
'error_type' => get_class($e),
|
||||
'error_message' => $e->getMessage(),
|
||||
'stack_trace' => $e->getTraceAsString(),
|
||||
'status' => 'pending',
|
||||
]);
|
||||
|
||||
try {
|
||||
\App\Jobs\AiHealerJob::dispatchSync(
|
||||
$log->id,
|
||||
$e->getFile(),
|
||||
$e->getLine()
|
||||
);
|
||||
} catch (\Throwable $inner) {
|
||||
$log->update([
|
||||
'status' => 'failed',
|
||||
'ai_diagnosis' => 'Healer dispatch crashed: ' . $inner->getMessage(),
|
||||
'action_taken' => 'Pipeline error',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $err) {
|
||||
// Silently ignore — never let the interceptor break error reporting.
|
||||
}
|
||||
}
|
||||
|
||||
if (app()->bound('sentry') && app()->environment('production', 'staging')) {
|
||||
app('sentry')->captureException($e);
|
||||
}
|
||||
});
|
||||
})
|
||||
->create();
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
use App\Providers\AppServiceProvider;
|
||||
use App\Providers\Filament\AdminPanelProvider;
|
||||
use App\Providers\HorizonServiceProvider;
|
||||
use App\Providers\SystemConfigServiceProvider;
|
||||
use App\Providers\TelescopeServiceProvider;
|
||||
use L5Swagger\L5SwaggerServiceProvider;
|
||||
|
||||
return [
|
||||
AppServiceProvider::class,
|
||||
AdminPanelProvider::class,
|
||||
HorizonServiceProvider::class,
|
||||
SystemConfigServiceProvider::class,
|
||||
TelescopeServiceProvider::class,
|
||||
L5SwaggerServiceProvider::class,
|
||||
];
|
||||
Reference in New Issue
Block a user