feat: Complete Woles Framework v1.0 with enterprise-grade UI

- Add comprehensive error handling system with custom error pages
- Implement professional enterprise-style design with Tailwind CSS
- Create modular HMVC architecture with clean separation of concerns
- Add security features: CSRF protection, XSS filtering, Argon2ID hashing
- Include CLI tools for development workflow
- Add error reporting dashboard with system monitoring
- Implement responsive design with consistent slate color scheme
- Replace all emoji icons with professional SVG icons
- Add comprehensive test suite with PHPUnit
- Include database migrations and seeders
- Add proper exception handling with fallback pages
- Implement template engine with custom syntax support
- Add helper functions and facades for clean code
- Include proper logging and debugging capabilities
This commit is contained in:
mwpn
2025-10-11 07:08:23 +07:00
commit 0b42271bfe
90 changed files with 8315 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Modules\Error;
use App\Core\Controller as BaseController;
class Controller extends BaseController
{
/**
* 404 Not Found page
*/
public function notFound()
{
return $this->view('Error.view.404', [
'title' => '404 - Page Not Found',
'message' => 'The page you are looking for could not be found.',
'code' => 404
], 404);
}
/**
* 500 Internal Server Error page
*/
public function serverError($exception = null)
{
return $this->view('Error.view.500', [
'title' => '500 - Server Error',
'message' => 'Something went wrong on our end.',
'code' => 500,
'exception' => $exception
], 500);
}
/**
* 403 Forbidden page
*/
public function forbidden()
{
return $this->view('Error.view.403', [
'title' => '403 - Forbidden',
'message' => 'You do not have permission to access this resource.',
'code' => 403
], 403);
}
/**
* 401 Unauthorized page
*/
public function unauthorized()
{
return $this->view('Error.view.401', [
'title' => '401 - Unauthorized',
'message' => 'You need to be authenticated to access this resource.',
'code' => 401
], 401);
}
/**
* 419 CSRF Token Mismatch
*/
public function csrfMismatch()
{
return $this->view('Error.view.419', [
'title' => '419 - CSRF Token Mismatch',
'message' => 'Your session has expired. Please try again.',
'code' => 419
], 419);
}
/**
* Error Reports page
*/
public function reports()
{
return $this->view('Error.view.reports', [
'title' => 'Error Reports - Woles Framework'
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Error Routes
*/
// 404 Not Found
$router->get('/404', 'Error\Controller@notFound');
// 500 Server Error
$router->get('/500', 'Error\Controller@serverError');
// 403 Forbidden
$router->get('/403', 'Error\Controller@forbidden');
// 401 Unauthorized
$router->get('/401', 'Error\Controller@unauthorized');
// 419 CSRF Token Mismatch
$router->get('/419', 'Error\Controller@csrfMismatch');
// Error Reports
$router->get('/error-reports', 'Error\Controller@reports');

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
</head>
<body class="font-sans bg-slate-50 min-h-screen">
<div class="min-h-screen flex items-center justify-center px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
<div class="text-center">
<div class="mx-auto h-24 w-24 bg-slate-100 rounded-full flex items-center justify-center mb-6">
<svg class="h-12 w-12 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
</svg>
</div>
<h1 class="text-6xl font-bold text-slate-900 mb-2">{{ $code }}</h1>
<h2 class="text-2xl font-semibold text-slate-900 mb-4">Authentication Required</h2>
<p class="text-slate-600 mb-8">{{ $message }}</p>
<div class="space-y-4">
<a href="/login" class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-slate-900 hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-900">
Sign In
</a>
<a href="/register" class="w-full flex justify-center py-3 px-4 border border-slate-300 rounded-md shadow-sm text-sm font-medium text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
Create Account
</a>
</div>
<div class="mt-8 text-sm text-slate-500">
You need to be logged in to access this page.
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
</head>
<body class="font-sans bg-slate-50 min-h-screen">
<div class="min-h-screen flex items-center justify-center px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
<div class="text-center">
<div class="mx-auto h-24 w-24 bg-slate-100 rounded-full flex items-center justify-center mb-6">
<svg class="h-12 w-12 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L18.364 5.636M5.636 18.364l12.728-12.728"></path>
</svg>
</div>
<h1 class="text-6xl font-bold text-slate-900 mb-2">{{ $code }}</h1>
<h2 class="text-2xl font-semibold text-slate-900 mb-4">Access Forbidden</h2>
<p class="text-slate-600 mb-8">{{ $message }}</p>
<div class="space-y-4">
<a href="/login" class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-slate-900 hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-900">
Sign In
</a>
<a href="/" class="w-full flex justify-center py-3 px-4 border border-slate-300 rounded-md shadow-sm text-sm font-medium text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
Return to Home
</a>
</div>
<div class="mt-8 text-sm text-slate-500">
Contact your administrator if you believe this is an error.
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
</head>
<body class="font-sans bg-slate-50 min-h-screen">
<div class="min-h-screen flex items-center justify-center px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
<div class="text-center">
<div class="mx-auto h-24 w-24 bg-slate-100 rounded-full flex items-center justify-center mb-6">
<svg class="h-12 w-12 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 12h6m-6-4h6m2 5.291A7.962 7.962 0 0112 15c-2.34 0-4.29-1.009-5.824-2.709M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
</div>
<h1 class="text-6xl font-bold text-slate-900 mb-2">{{ $code }}</h1>
<h2 class="text-2xl font-semibold text-slate-900 mb-4">Page Not Found</h2>
<p class="text-slate-600 mb-8">{{ $message }}</p>
<div class="space-y-4">
<a href="/" class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-slate-900 hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-900">
Return to Home
</a>
<button onclick="history.back()" class="w-full flex justify-center py-3 px-4 border border-slate-300 rounded-md shadow-sm text-sm font-medium text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
Go Back
</button>
</div>
<div class="mt-8 text-sm text-slate-500">
If you believe this is an error, please contact support.
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
</head>
<body class="font-sans bg-slate-50 min-h-screen">
<div class="min-h-screen flex items-center justify-center px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
<div class="text-center">
<div class="mx-auto h-24 w-24 bg-slate-100 rounded-full flex items-center justify-center mb-6">
<svg class="h-12 w-12 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
</div>
<h1 class="text-6xl font-bold text-slate-900 mb-2">{{ $code }}</h1>
<h2 class="text-2xl font-semibold text-slate-900 mb-4">Session Expired</h2>
<p class="text-slate-600 mb-8">{{ $message }}</p>
<div class="space-y-4">
<button onclick="location.reload()" class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-slate-900 hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-900">
Refresh Page
</button>
<a href="/" class="w-full flex justify-center py-3 px-4 border border-slate-300 rounded-md shadow-sm text-sm font-medium text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
Return to Home
</a>
</div>
<div class="mt-8 text-sm text-slate-500">
Your session has expired. Please refresh the page and try again.
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
</head>
<body class="font-sans bg-slate-50 min-h-screen">
<div class="min-h-screen flex items-center justify-center px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
<div class="text-center">
<div class="mx-auto h-24 w-24 bg-slate-100 rounded-full flex items-center justify-center mb-6">
<svg class="h-12 w-12 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
</svg>
</div>
<h1 class="text-6xl font-bold text-slate-900 mb-2">{{ $code }}</h1>
<h2 class="text-2xl font-semibold text-slate-900 mb-4">Server Error</h2>
<p class="text-slate-600 mb-8">{{ $message }}</p>
<div class="space-y-4">
<a href="/" class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-slate-900 hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-900">
Return to Home
</a>
<button onclick="location.reload()" class="w-full flex justify-center py-3 px-4 border border-slate-300 rounded-md shadow-sm text-sm font-medium text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500">
Try Again
</button>
</div>
<!-- Debug Info (only in development) -->
<?php if (getenv('APP_DEBUG') === 'true' && isset($exception)): ?>
<div class="mt-8 p-4 bg-red-50 border border-red-200 rounded-lg text-left">
<h3 class="text-sm font-medium text-red-800 mb-2">Debug Information:</h3>
<div class="text-xs text-red-700 font-mono">
<div><strong>Message:</strong> <?php echo htmlspecialchars($exception->getMessage()); ?></div>
<div><strong>File:</strong> <?php echo htmlspecialchars($exception->getFile()); ?></div>
<div><strong>Line:</strong> <?php echo $exception->getLine(); ?></div>
</div>
</div>
<?php endif; ?>
<div class="mt-8 text-sm text-slate-500">
We're working to fix this issue. Please try again later.
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,203 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Error Reports - Woles Framework</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
'sans': ['Inter', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
</head>
<body class="font-sans bg-slate-50 min-h-screen">
<div class="max-w-7xl mx-auto px-4 py-8">
<!-- Header -->
<div class="mb-8">
<div class="flex items-center justify-between">
<div>
<h1 class="text-3xl font-bold text-slate-900">Error Reports</h1>
<p class="text-slate-600 mt-2">System error logs and debugging information</p>
</div>
<div class="flex space-x-4">
<a href="/" class="bg-slate-900 hover:bg-slate-800 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
Back to Home
</a>
<button onclick="location.reload()" class="bg-white border border-slate-300 hover:bg-slate-50 text-slate-700 px-4 py-2 rounded-md text-sm font-medium transition-colors">
Refresh
</button>
</div>
</div>
</div>
<!-- System Info -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-lg shadow-sm border border-slate-200 p-6">
<div class="flex items-center">
<div class="w-12 h-12 bg-slate-100 rounded-lg flex items-center justify-center mr-4">
<svg class="w-6 h-6 text-slate-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path>
</svg>
</div>
<div>
<h3 class="font-semibold text-slate-900">PHP Version</h3>
<p class="text-2xl font-bold text-slate-900"><?php echo PHP_VERSION; ?></p>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow-sm border border-slate-200 p-6">
<div class="flex items-center">
<div class="w-12 h-12 bg-slate-100 rounded-lg flex items-center justify-center mr-4">
<svg class="w-6 h-6 text-slate-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4"></path>
</svg>
</div>
<div>
<h3 class="font-semibold text-slate-900">Memory Usage</h3>
<p class="text-2xl font-bold text-slate-900"><?php echo round(memory_get_usage(true) / 1024 / 1024, 2); ?>MB</p>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow-sm border border-slate-200 p-6">
<div class="flex items-center">
<div class="w-12 h-12 bg-slate-100 rounded-lg flex items-center justify-center mr-4">
<svg class="w-6 h-6 text-slate-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
</svg>
</div>
<div>
<h3 class="font-semibold text-slate-900">Framework</h3>
<p class="text-2xl font-bold text-slate-900">Woles v1.0.0</p>
</div>
</div>
</div>
</div>
<!-- Error Log -->
<div class="bg-white rounded-lg shadow-sm border border-slate-200">
<div class="px-6 py-4 border-b border-slate-200">
<h2 class="text-xl font-semibold text-slate-900">Error Log</h2>
<p class="text-slate-600 text-sm">Recent error entries from the system log</p>
</div>
<div class="p-6">
<?php
$logFile = storage_path('logs/error.log');
if (file_exists($logFile)) {
$logContent = file_get_contents($logFile);
if (!empty($logContent)) {
$entries = explode("\n\n", trim($logContent));
$entries = array_reverse(array_filter($entries)); // Reverse to show newest first
if (count($entries) > 0) {
echo '<div class="space-y-4">';
foreach (array_slice($entries, 0, 10) as $entry) { // Show last 10 entries
$lines = explode("\n", $entry);
if (count($lines) >= 2) {
$timestamp = $lines[0];
$error = $lines[1];
$file = isset($lines[2]) ? $lines[2] : '';
echo '<div class="bg-red-50 border border-red-200 rounded-lg p-4">';
echo '<div class="flex items-start justify-between">';
echo '<div class="flex-1">';
echo '<div class="text-sm text-red-600 font-medium">' . htmlspecialchars($timestamp) . '</div>';
echo '<div class="text-red-800 font-semibold mt-1">' . htmlspecialchars($error) . '</div>';
if ($file) {
echo '<div class="text-sm text-red-600 mt-1">' . htmlspecialchars($file) . '</div>';
}
echo '</div>';
echo '<div class="text-2xl ml-4">🐛</div>';
echo '</div>';
echo '</div>';
}
}
echo '</div>';
} else {
echo '<div class="text-center py-12">';
echo '<div class="text-6xl mb-4">✅</div>';
echo '<h3 class="text-lg font-semibold text-gray-900 mb-2">No Errors Found</h3>';
echo '<p class="text-gray-600">The system is running smoothly with no recent errors.</p>';
echo '</div>';
}
} else {
echo '<div class="text-center py-12">';
echo '<div class="text-6xl mb-4">✅</div>';
echo '<h3 class="text-lg font-semibold text-gray-900 mb-2">No Errors Found</h3>';
echo '<p class="text-gray-600">The system is running smoothly with no recent errors.</p>';
echo '</div>';
}
} else {
echo '<div class="text-center py-12">';
echo '<div class="text-6xl mb-4">📝</div>';
echo '<h3 class="text-lg font-semibold text-gray-900 mb-2">No Log File</h3>';
echo '<p class="text-gray-600">Error log file does not exist yet. Errors will appear here when they occur.</p>';
echo '</div>';
}
?>
</div>
</div>
<!-- Debug Information -->
<div class="mt-8 bg-white rounded-lg shadow-sm border border-gray-200">
<div class="px-6 py-4 border-b border-gray-200">
<h2 class="text-xl font-semibold text-gray-900">Debug Information</h2>
<p class="text-gray-600 text-sm">System configuration and environment details</p>
</div>
<div class="p-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 class="font-semibold text-gray-900 mb-3">Environment</h3>
<div class="space-y-2 text-sm">
<div class="flex justify-between">
<span class="text-gray-600">Environment:</span>
<span class="font-medium"><?php echo getenv('APP_ENV') ?: 'development'; ?></span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Debug Mode:</span>
<span class="font-medium"><?php echo getenv('APP_DEBUG') === 'true' ? 'Enabled' : 'Disabled'; ?></span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Log Level:</span>
<span class="font-medium"><?php echo getenv('LOG_LEVEL') ?: 'debug'; ?></span>
</div>
</div>
</div>
<div>
<h3 class="font-semibold text-gray-900 mb-3">System</h3>
<div class="space-y-2 text-sm">
<div class="flex justify-between">
<span class="text-gray-600">Server:</span>
<span class="font-medium"><?php echo $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown'; ?></span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Document Root:</span>
<span class="font-medium"><?php echo $_SERVER['DOCUMENT_ROOT'] ?? 'Unknown'; ?></span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Current Time:</span>
<span class="font-medium"><?php echo date('Y-m-d H:i:s'); ?></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>