boilercraft 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +171 -0
  3. package/bin/boilercraft.js +110 -0
  4. package/cli/app.js +596 -0
  5. package/cli/ui.js +356 -0
  6. package/docs/STACK_ENGINE.md +93 -0
  7. package/docs/assets/cli-create.svg +52 -0
  8. package/docs/assets/cli-menu.svg +47 -0
  9. package/docs/stacks/dotnet-core.md +69 -0
  10. package/docs/stacks/laravel-vue.md +46 -0
  11. package/docs/stacks/nextjs.md +58 -0
  12. package/docs/stacks/node-express.md +58 -0
  13. package/docs/stacks/raw-php.md +130 -0
  14. package/main.js +82 -0
  15. package/package.json +86 -0
  16. package/public/index.html +721 -0
  17. package/public/logo.png +17 -0
  18. package/public/logo.svg +17 -0
  19. package/server.js +84 -0
  20. package/services/componentGenerator.js +195 -0
  21. package/services/engine/scaffoldEngine.js +517 -0
  22. package/services/engine/toolInstaller.js +232 -0
  23. package/services/engine/versionCatalog.js +115 -0
  24. package/services/generate.js +46 -0
  25. package/services/projectGenerator.js +686 -0
  26. package/services/readmeGenerator.js +221 -0
  27. package/services/themeGenerator.js +150 -0
  28. package/services/versionResolver.js +176 -0
  29. package/stacks/dotnet-core/overlays/api/Controllers/ProductsController.cs +33 -0
  30. package/stacks/dotnet-core/overlays/api/Program.cs +33 -0
  31. package/stacks/dotnet-core/overlays/api/wwwroot/index.html +38 -0
  32. package/stacks/dotnet-core/overlays/api-auth/Controllers/AuthController.cs +87 -0
  33. package/stacks/dotnet-core/overlays/common/Data/ApplicationDbContext.cs +25 -0
  34. package/stacks/dotnet-core/overlays/common/Models/Product.cs +19 -0
  35. package/stacks/dotnet-core/overlays/mvc/Controllers/ProductsController.cs +84 -0
  36. package/stacks/dotnet-core/overlays/mvc/Views/Home/Index.cshtml +23 -0
  37. package/stacks/dotnet-core/overlays/mvc/Views/Products/Create.cshtml +16 -0
  38. package/stacks/dotnet-core/overlays/mvc/Views/Products/Delete.cshtml +16 -0
  39. package/stacks/dotnet-core/overlays/mvc/Views/Products/Edit.cshtml +17 -0
  40. package/stacks/dotnet-core/overlays/mvc/Views/Products/Index.cshtml +46 -0
  41. package/stacks/dotnet-core/overlays/mvc/Views/Products/_Form.cshtml +19 -0
  42. package/stacks/dotnet-core/overlays/mvc-auth/Controllers/AccountController.cs +98 -0
  43. package/stacks/dotnet-core/overlays/mvc-auth/Models/AppUser.cs +48 -0
  44. package/stacks/dotnet-core/overlays/mvc-auth/Views/Account/Login.cshtml +35 -0
  45. package/stacks/dotnet-core/overlays/mvc-auth/Views/Account/Register.cshtml +41 -0
  46. package/stacks/dotnet-core/overlays/mvc-auth/Views/Shared/_AuthNav.cshtml +22 -0
  47. package/stacks/dotnet-core/snippets/packages-auth.xml +4 -0
  48. package/stacks/dotnet-core/snippets/packages-common.xml +5 -0
  49. package/stacks/dotnet-core/snippets/packages-ef.xml +4 -0
  50. package/stacks/dotnet-core/snippets/packages-mssql.xml +4 -0
  51. package/stacks/dotnet-core/snippets/packages-mysql.xml +4 -0
  52. package/stacks/dotnet-core/snippets/packages-swagger.xml +4 -0
  53. package/stacks/dotnet-core/stack.json +426 -0
  54. package/stacks/laravel/overlays/auth/app/Http/Controllers/Api/AuthController.php +67 -0
  55. package/stacks/laravel/overlays/common/app/Http/Controllers/BoilerCraftController.php +14 -0
  56. package/stacks/laravel/overlays/common/resources/views/boilercraft.blade.php +36 -0
  57. package/stacks/laravel/overlays/inertia-common/resources/views/app.blade.php +15 -0
  58. package/stacks/laravel/overlays/inertia-react/resources/js/Pages/Welcome.jsx +18 -0
  59. package/stacks/laravel/overlays/inertia-react/resources/js/app.jsx +13 -0
  60. package/stacks/laravel/overlays/inertia-vue/resources/js/Pages/Welcome.vue +23 -0
  61. package/stacks/laravel/overlays/inertia-vue/resources/js/app.js +13 -0
  62. package/stacks/laravel/snippets/api-routes.php +9 -0
  63. package/stacks/laravel/snippets/web-routes-inertia.php +7 -0
  64. package/stacks/laravel/snippets/web-routes.php +4 -0
  65. package/stacks/laravel/stack.json +477 -0
  66. package/stacks/nextjs/overlays/auth/src/lib/auth.js +36 -0
  67. package/stacks/nextjs/overlays/auth-app/src/app/api/auth/login/route.js +11 -0
  68. package/stacks/nextjs/overlays/auth-app/src/app/api/auth/register/route.js +14 -0
  69. package/stacks/nextjs/overlays/auth-pages/src/pages/api/auth/login.js +14 -0
  70. package/stacks/nextjs/overlays/auth-pages/src/pages/api/auth/register.js +17 -0
  71. package/stacks/nextjs/overlays/common/.env.example +3 -0
  72. package/stacks/nextjs/overlays/common/.env.local +3 -0
  73. package/stacks/nextjs/overlays/db/mongodb/src/lib/db.js +12 -0
  74. package/stacks/nextjs/overlays/db/mssql/src/lib/db.js +17 -0
  75. package/stacks/nextjs/overlays/db/mysql/src/lib/db.js +13 -0
  76. package/stacks/nextjs/overlays/router-app/src/app/api/health/route.js +10 -0
  77. package/stacks/nextjs/overlays/router-app/src/app/layout.js +16 -0
  78. package/stacks/nextjs/overlays/router-app/src/app/page.js +19 -0
  79. package/stacks/nextjs/overlays/router-pages/src/pages/_app.js +7 -0
  80. package/stacks/nextjs/overlays/router-pages/src/pages/_document.js +13 -0
  81. package/stacks/nextjs/overlays/router-pages/src/pages/api/health.js +8 -0
  82. package/stacks/nextjs/overlays/router-pages/src/pages/index.js +27 -0
  83. package/stacks/nextjs/stack.json +257 -0
  84. package/stacks/node-express/overlays/auth/src/controllers/authController.js +53 -0
  85. package/stacks/node-express/overlays/auth/src/middlewares/auth.js +36 -0
  86. package/stacks/node-express/overlays/auth/src/routes/authRoutes.js +16 -0
  87. package/stacks/node-express/overlays/common/.env.example +5 -0
  88. package/stacks/node-express/overlays/common/public/index.html +31 -0
  89. package/stacks/node-express/overlays/common/src/server.js +32 -0
  90. package/stacks/node-express/overlays/db/mongodb/src/db.js +13 -0
  91. package/stacks/node-express/overlays/db/mssql/src/db.js +22 -0
  92. package/stacks/node-express/overlays/db/mysql/src/db.js +22 -0
  93. package/stacks/node-express/stack.json +165 -0
  94. package/templates/dotnet-bootstrap-mssql/Controllers/AuthController.cs +74 -0
  95. package/templates/dotnet-bootstrap-mssql/Controllers/ProductsController.cs +33 -0
  96. package/templates/dotnet-bootstrap-mssql/Data/ApplicationDbContext.cs +24 -0
  97. package/templates/dotnet-bootstrap-mssql/Models/Product.cs +10 -0
  98. package/templates/dotnet-core/Controllers/AuthController.cs +74 -0
  99. package/templates/laravel-full/app/Http/Controllers/AuthController.php +79 -0
  100. package/templates/laravel-full/app/Http/Controllers/HomeController.php +22 -0
  101. package/templates/laravel-full/app/Models/User.php +49 -0
  102. package/templates/laravel-full/artisan +22 -0
  103. package/templates/laravel-full/bootstrap/app.php +21 -0
  104. package/templates/laravel-full/config/database.php +54 -0
  105. package/templates/laravel-full/database/migrations/2024_01_01_000001_create_users_table.php +27 -0
  106. package/templates/laravel-full/public/index.php +17 -0
  107. package/templates/laravel-full/resources/css/app.css +3 -0
  108. package/templates/laravel-full/resources/js/Pages/Home.vue +76 -0
  109. package/templates/laravel-full/resources/js/app.js +21 -0
  110. package/templates/laravel-full/resources/js/bootstrap.js +3 -0
  111. package/templates/laravel-full/resources/views/app.blade.php +15 -0
  112. package/templates/laravel-full/routes/api.php +8 -0
  113. package/templates/laravel-full/routes/console.php +7 -0
  114. package/templates/laravel-full/routes/web.php +24 -0
  115. package/templates/laravel-full/tailwind.config.js +12 -0
  116. package/templates/laravel-full/vite.config.js +20 -0
  117. package/templates/laravel-vue/app/Http/Controllers/Auth/AuthenticatedSessionController.php +43 -0
  118. package/templates/laravel-vue-mysql/app/Http/Controllers/HomeController.php +25 -0
  119. package/templates/laravel-vue-mysql/resources/js/Pages/Home.vue +70 -0
  120. package/templates/nextjs/src/app/api/auth/login/route.js +28 -0
  121. package/templates/nextjs-mongodb/src/app/api/health/route.js +17 -0
  122. package/templates/nextjs-mongodb/src/lib/mongodb.js +18 -0
  123. package/templates/nextjs-mssql/src/app/api/health/route.js +24 -0
  124. package/templates/nextjs-mssql/src/lib/mssql.js +38 -0
  125. package/templates/node-express/src/controllers/authController.js +53 -0
  126. package/templates/node-express/src/middlewares/auth.js +36 -0
  127. package/templates/node-express/src/routes/authRoutes.js +16 -0
  128. package/templates/node-mongodb/src/controllers/userController.js +30 -0
  129. package/templates/node-mongodb/src/middlewares/errorHandler.js +8 -0
  130. package/templates/node-mongodb/src/models/User.js +23 -0
  131. package/templates/node-mongodb/src/routes/api.js +9 -0
  132. package/templates/raw-php-mysql/app/Controllers/AuthController.php +73 -0
  133. package/templates/raw-php-mysql/app/Controllers/HomeController.php +65 -0
  134. package/templates/raw-php-mysql/app/Models/User.php +60 -0
  135. package/templates/raw-php-mysql/app/Views/404.php +15 -0
  136. package/templates/raw-php-mysql/app/Views/auth/login.php +66 -0
  137. package/templates/raw-php-mysql/app/Views/auth/register.php +71 -0
  138. package/templates/raw-php-mysql/app/Views/dashboard.php +50 -0
  139. package/templates/raw-php-mysql/app/Views/home.php +83 -0
  140. package/templates/raw-php-mysql/config/Auth.php +62 -0
  141. package/templates/raw-php-mysql/config/Database.php +100 -0
  142. package/templates/raw-php-mysql/config/Env.php +30 -0
  143. package/templates/raw-php-mysql/config/Middleware.php +53 -0
  144. package/templates/raw-php-mysql/config/QueryBuilder.php +109 -0
  145. package/templates/raw-php-mysql/config/Router.php +33 -0
  146. package/templates/raw-php-mysql/public/index.php +57 -0
@@ -0,0 +1,73 @@
1
+ <?php
2
+ namespace App\Controllers;
3
+
4
+ use App\Models\User;
5
+ use App\Config\Auth;
6
+
7
+ class AuthController {
8
+ public function showLogin(): void {
9
+ require __DIR__ . '/../Views/auth/login.php';
10
+ }
11
+
12
+ public function login(): void {
13
+ header('Content-Type: application/json');
14
+ $raw = file_get_contents('php://input');
15
+ $data = json_decode($raw, true) ?: $_POST;
16
+
17
+ $email = trim($data['email'] ?? '');
18
+ $password = $data['password'] ?? '';
19
+
20
+ $userModel = new User();
21
+ $user = $userModel->findByEmail($email);
22
+
23
+ if ($user && password_verify($password, $user['password'])) {
24
+ Auth::login($user);
25
+ echo json_encode(['success' => true, 'redirect' => '/dashboard']);
26
+ } else {
27
+ http_response_code(401);
28
+ echo json_encode(['success' => false, 'error' => 'Invalid email or password']);
29
+ }
30
+ }
31
+
32
+ public function showRegister(): void {
33
+ require __DIR__ . '/../Views/auth/register.php';
34
+ }
35
+
36
+ public function register(): void {
37
+ header('Content-Type: application/json');
38
+ $raw = file_get_contents('php://input');
39
+ $data = json_decode($raw, true) ?: $_POST;
40
+
41
+ $name = trim($data['name'] ?? '');
42
+ $email = trim($data['email'] ?? '');
43
+ $password = $data['password'] ?? '';
44
+ $role = $data['role'] ?? 'user';
45
+
46
+ if (empty($name) || empty($email) || strlen($password) < 6) {
47
+ http_response_code(422);
48
+ echo json_encode(['success' => false, 'error' => 'Name, valid email and min 6 char password required.']);
49
+ return;
50
+ }
51
+
52
+ $userModel = new User();
53
+ if ($userModel->findByEmail($email)) {
54
+ http_response_code(409);
55
+ echo json_encode(['success' => false, 'error' => 'Email already registered.']);
56
+ return;
57
+ }
58
+
59
+ $hashed = password_hash($password, PASSWORD_BCRYPT);
60
+ $userModel->createWithPassword($name, $email, $hashed, $role);
61
+
62
+ $newUser = $userModel->findByEmail($email);
63
+ Auth::login($newUser);
64
+
65
+ echo json_encode(['success' => true, 'redirect' => '/dashboard']);
66
+ }
67
+
68
+ public function logout(): void {
69
+ Auth::logout();
70
+ header('Location: /login');
71
+ exit;
72
+ }
73
+ }
@@ -0,0 +1,65 @@
1
+ <?php
2
+ namespace App\Controllers;
3
+
4
+ use App\Models\User;
5
+
6
+ class HomeController {
7
+ public function index(): void {
8
+ $appName = "{{APP_TITLE}}";
9
+ $appDesc = "{{APP_DESC}}";
10
+ $author = "{{AUTHOR}}";
11
+
12
+ $userModel = new User();
13
+ $users = $userModel->all();
14
+
15
+ require __DIR__ . '/../Views/home.php';
16
+ }
17
+
18
+ /**
19
+ * AJAX Endpoint for User Registration
20
+ */
21
+ public function apiCreateUser(): void {
22
+ header('Content-Type: application/json');
23
+ $raw = file_get_contents('php://input');
24
+ $data = json_decode($raw, true) ?: $_POST;
25
+
26
+ $name = trim($data['name'] ?? '');
27
+ $email = trim($data['email'] ?? '');
28
+
29
+ if (empty($name) || empty($email)) {
30
+ http_response_code(422);
31
+ echo json_encode(['success' => false, 'error' => 'Name and Email are required.']);
32
+ return;
33
+ }
34
+
35
+ try {
36
+ $userModel = new User();
37
+ $userModel->create($name, $email);
38
+ echo json_encode(['success' => true, 'message' => 'User created via AJAX successfully!']);
39
+ } catch (\Exception $e) {
40
+ http_response_code(500);
41
+ echo json_encode(['success' => false, 'error' => $e->getMessage()]);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * AJAX Endpoint for fetching Users list
47
+ */
48
+ public function apiGetUsers(): void {
49
+ header('Content-Type: application/json');
50
+ $userModel = new User();
51
+ $users = $userModel->all();
52
+ echo json_encode(['success' => true, 'data' => $users]);
53
+ }
54
+
55
+ public function apiHealth(): void {
56
+ header('Content-Type: application/json');
57
+ echo json_encode([
58
+ 'status' => 'online',
59
+ 'platform' => 'Raw PHP MVC',
60
+ 'database' => 'MySQL PDO',
61
+ 'ajax_support' => true,
62
+ 'timestamp' => time()
63
+ ]);
64
+ }
65
+ }
@@ -0,0 +1,60 @@
1
+ <?php
2
+ namespace App\Models;
3
+
4
+ use App\Config\QueryBuilder;
5
+ use App\Config\Database;
6
+
7
+ class User {
8
+ protected string $table = 'users';
9
+
10
+ public function __construct() {
11
+ $this->initSchema();
12
+ }
13
+
14
+ private function initSchema(): void {
15
+ $sql = "CREATE TABLE IF NOT EXISTS {$this->table} (
16
+ id INT AUTO_INCREMENT PRIMARY KEY,
17
+ name VARCHAR(100) NOT NULL,
18
+ email VARCHAR(150) UNIQUE NOT NULL,
19
+ password VARCHAR(255) NULL,
20
+ role VARCHAR(50) DEFAULT 'user',
21
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
22
+ ) ENGINE=INNODB;";
23
+ Database::execute($sql);
24
+ }
25
+
26
+ public function all(): array {
27
+ return QueryBuilder::table($this->table)
28
+ ->orderBy('id', 'DESC')
29
+ ->limit(20)
30
+ ->get();
31
+ }
32
+
33
+ public function find(int $id): ?array {
34
+ return QueryBuilder::table($this->table)
35
+ ->where('id', $id)
36
+ ->first();
37
+ }
38
+
39
+ public function findByEmail(string $email): ?array {
40
+ return QueryBuilder::table($this->table)
41
+ ->where('email', $email)
42
+ ->first();
43
+ }
44
+
45
+ public function createWithPassword(string $name, string $email, string $passwordHash, string $role = 'user'): bool {
46
+ return QueryBuilder::table($this->table)->insert([
47
+ 'name' => $name,
48
+ 'email' => $email,
49
+ 'password' => $passwordHash,
50
+ 'role' => $role
51
+ ]);
52
+ }
53
+
54
+ public function create(string $name, string $email): bool {
55
+ return QueryBuilder::table($this->table)->insert([
56
+ 'name' => $name,
57
+ 'email' => $email
58
+ ]);
59
+ }
60
+ }
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>404 Not Found</title>
6
+ <link rel="stylesheet" href="/css/theme.css">
7
+ </head>
8
+ <body style="display: flex; height: 100vh; align-items: center; justify-content: center; text-align: center;">
9
+ <div>
10
+ <h1 style="font-size: 4rem; color: var(--color-primary);">404</h1>
11
+ <p style="color: var(--color-text-muted);">Page Not Found</p>
12
+ <a href="/" style="color: var(--color-primary); text-decoration: underline; margin-top: 1rem; display: inline-block;">Return Home</a>
13
+ </div>
14
+ </body>
15
+ </html>
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Login — Access Account</title>
7
+ <link rel="stylesheet" href="/css/theme.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
10
+ </head>
11
+ <body class="min-h-screen flex items-center justify-center p-6 bg-[var(--color-bg)] text-[var(--color-text)]">
12
+ <div class="max-w-md w-full p-8 rounded-2xl bg-[var(--color-surface)] border border-[var(--color-border)] shadow-2xl">
13
+ <h2 class="text-2xl font-bold mb-1">Welcome Back</h2>
14
+ <p class="text-sm text-[var(--color-text-muted)] mb-6">Sign in to your authenticated account</p>
15
+
16
+ <form id="loginForm" class="space-y-4">
17
+ <div>
18
+ <label class="block text-xs font-semibold mb-1">Email Address</label>
19
+ <input type="email" id="email" required class="w-full px-4 py-2.5 rounded-xl border border-[var(--color-border)] bg-[var(--color-bg)] text-[var(--color-text)] outline-none focus:border-[var(--color-primary)]">
20
+ </div>
21
+ <div>
22
+ <label class="block text-xs font-semibold mb-1">Password</label>
23
+ <input type="password" id="password" required class="w-full px-4 py-2.5 rounded-xl border border-[var(--color-border)] bg-[var(--color-bg)] text-[var(--color-text)] outline-none focus:border-[var(--color-primary)]">
24
+ </div>
25
+
26
+ <div id="loginMsg" class="text-xs font-semibold"></div>
27
+
28
+ <button type="submit" id="btnLogin" class="w-full py-3 rounded-xl bg-[var(--color-primary)] text-white font-bold hover:opacity-95 transition shadow-lg shadow-[var(--color-primary)]/25">
29
+ Sign In
30
+ </button>
31
+ </form>
32
+
33
+ <p class="text-xs text-center mt-6 text-[var(--color-text-muted)]">
34
+ Don't have an account? <a href="/register" class="text-[var(--color-primary)] font-bold">Register</a>
35
+ </p>
36
+ </div>
37
+
38
+ <script>
39
+ $('#loginForm').on('submit', function(e) {
40
+ e.preventDefault();
41
+ const btn = $('#btnLogin');
42
+ const msg = $('#loginMsg');
43
+ btn.prop('disabled', true).text('Verifying...');
44
+
45
+ $.ajax({
46
+ url: '/api/login',
47
+ type: 'POST',
48
+ contentType: 'application/json',
49
+ data: JSON.stringify({
50
+ email: $('#email').val(),
51
+ password: $('#password').val()
52
+ }),
53
+ success: function(res) {
54
+ msg.html('<span class="text-emerald-500">✓ Login successful! Redirecting...</span>');
55
+ window.location.href = res.redirect || '/dashboard';
56
+ },
57
+ error: function(xhr) {
58
+ const err = xhr.responseJSON ? xhr.responseJSON.error : 'Invalid credentials';
59
+ msg.html('<span class="text-rose-500">✗ ' + err + '</span>');
60
+ btn.prop('disabled', false).text('Sign In');
61
+ }
62
+ });
63
+ });
64
+ </script>
65
+ </body>
66
+ </html>
@@ -0,0 +1,71 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Register — Create Account</title>
7
+ <link rel="stylesheet" href="/css/theme.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
10
+ </head>
11
+ <body class="min-h-screen flex items-center justify-center p-6 bg-[var(--color-bg)] text-[var(--color-text)]">
12
+ <div class="max-w-md w-full p-8 rounded-2xl bg-[var(--color-surface)] border border-[var(--color-border)] shadow-2xl">
13
+ <h2 class="text-2xl font-bold mb-1">Create Account</h2>
14
+ <p class="text-sm text-[var(--color-text-muted)] mb-6">Register a new authenticated profile</p>
15
+
16
+ <form id="regForm" class="space-y-4">
17
+ <div>
18
+ <label class="block text-xs font-semibold mb-1">Full Name</label>
19
+ <input type="text" id="name" required class="w-full px-4 py-2.5 rounded-xl border border-[var(--color-border)] bg-[var(--color-bg)] text-[var(--color-text)] outline-none focus:border-[var(--color-primary)]">
20
+ </div>
21
+ <div>
22
+ <label class="block text-xs font-semibold mb-1">Email Address</label>
23
+ <input type="email" id="email" required class="w-full px-4 py-2.5 rounded-xl border border-[var(--color-border)] bg-[var(--color-bg)] text-[var(--color-text)] outline-none focus:border-[var(--color-primary)]">
24
+ </div>
25
+ <div>
26
+ <label class="block text-xs font-semibold mb-1">Password</label>
27
+ <input type="password" id="password" minlength="6" required class="w-full px-4 py-2.5 rounded-xl border border-[var(--color-border)] bg-[var(--color-bg)] text-[var(--color-text)] outline-none focus:border-[var(--color-primary)]">
28
+ </div>
29
+
30
+ <div id="regMsg" class="text-xs font-semibold"></div>
31
+
32
+ <button type="submit" id="btnReg" class="w-full py-3 rounded-xl bg-[var(--color-primary)] text-white font-bold hover:opacity-95 transition shadow-lg shadow-[var(--color-primary)]/25">
33
+ Register Now
34
+ </button>
35
+ </form>
36
+
37
+ <p class="text-xs text-center mt-6 text-[var(--color-text-muted)]">
38
+ Already registered? <a href="/login" class="text-[var(--color-primary)] font-bold">Login</a>
39
+ </p>
40
+ </div>
41
+
42
+ <script>
43
+ $('#regForm').on('submit', function(e) {
44
+ e.preventDefault();
45
+ const btn = $('#btnReg');
46
+ const msg = $('#regMsg');
47
+ btn.prop('disabled', true).text('Creating Account...');
48
+
49
+ $.ajax({
50
+ url: '/api/register',
51
+ type: 'POST',
52
+ contentType: 'application/json',
53
+ data: JSON.stringify({
54
+ name: $('#name').val(),
55
+ email: $('#email').val(),
56
+ password: $('#password').val()
57
+ }),
58
+ success: function(res) {
59
+ msg.html('<span class="text-emerald-500">✓ Account created! Redirecting...</span>');
60
+ window.location.href = res.redirect || '/dashboard';
61
+ },
62
+ error: function(xhr) {
63
+ const err = xhr.responseJSON ? xhr.responseJSON.error : 'Registration failed';
64
+ msg.html('<span class="text-rose-500">✗ ' + err + '</span>');
65
+ btn.prop('disabled', false).text('Register Now');
66
+ }
67
+ });
68
+ });
69
+ </script>
70
+ </body>
71
+ </html>
@@ -0,0 +1,50 @@
1
+ <?php
2
+ use App\Config\Auth;
3
+ $currentUser = Auth::user();
4
+ ?>
5
+ <!DOCTYPE html>
6
+ <html lang="en">
7
+ <head>
8
+ <meta charset="UTF-8">
9
+ <title>Dashboard — Authenticated Area</title>
10
+ <link rel="stylesheet" href="/css/theme.css">
11
+ <script src="https://cdn.tailwindcss.com"></script>
12
+ </head>
13
+ <body class="p-8 bg-[var(--color-bg)] text-[var(--color-text)] min-h-screen">
14
+ <div class="max-w-4xl mx-auto">
15
+ <div class="flex justify-between items-center pb-6 border-b border-[var(--color-border)] mb-8">
16
+ <div>
17
+ <h1 class="text-3xl font-extrabold">Protected Dashboard</h1>
18
+ <p class="text-sm text-[var(--color-text-muted)]">Session Authentication & Role Authorization Active</p>
19
+ </div>
20
+ <div class="flex items-center gap-4">
21
+ <span class="px-3 py-1 text-xs rounded-full bg-emerald-500/10 text-emerald-400 font-bold border border-emerald-500/20">
22
+ Role: <?= htmlspecialchars($currentUser['role']) ?>
23
+ </span>
24
+ <a href="/logout" class="px-4 py-2 rounded-xl border border-[var(--color-border)] text-sm font-semibold hover:bg-rose-500 hover:text-white transition">
25
+ Logout
26
+ </a>
27
+ </div>
28
+ </div>
29
+
30
+ <div class="p-6 rounded-2xl bg-[var(--color-surface)] border border-[var(--color-border)] shadow-xl mb-6">
31
+ <h3 class="font-bold text-lg mb-2">Welcome, <?= htmlspecialchars($currentUser['name']) ?>!</h3>
32
+ <p class="text-sm text-[var(--color-text-muted)] mb-4">You are authorized to view this page. Your email is <strong><?= htmlspecialchars($currentUser['email']) ?></strong>.</p>
33
+
34
+ <div class="p-4 rounded-xl bg-[var(--color-bg)] border border-[var(--color-border)] font-mono text-xs text-emerald-400">
35
+ // Session State<br>
36
+ User ID: <?= $currentUser['id'] ?><br>
37
+ Role: <?= $currentUser['role'] ?><br>
38
+ Guard: Middleware::auth() Passed
39
+ </div>
40
+ </div>
41
+
42
+ <?php if ($currentUser['role'] === 'admin'): ?>
43
+ <div class="p-6 rounded-2xl bg-amber-500/10 border border-amber-500/30 text-amber-200">
44
+ <h4 class="font-bold mb-1">👑 Admin Only Area</h4>
45
+ <p class="text-xs">This section is strictly rendered because your account has the 'admin' permission.</p>
46
+ </div>
47
+ <?php endif; ?>
48
+ </div>
49
+ </body>
50
+ </html>
@@ -0,0 +1,83 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="{{COLOR_MODE}}">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title><?= htmlspecialchars($appName) ?></title>
7
+ <link rel="stylesheet" href="/css/theme.css">
8
+ {{STYLESHEET_LINK}}
9
+ <!-- jQuery Support CDN -->
10
+ <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
11
+ </head>
12
+ <body class="p-6">
13
+ <div style="max-width: 900px; margin: 2rem auto; text-align: center;">
14
+ {{LOGO_HTML}}
15
+ <h1 style="font-size: 2.5rem; font-weight: 800; margin-bottom: 0.5rem;"><?= htmlspecialchars($appName) ?></h1>
16
+ <p style="color: var(--color-text-muted); font-size: 1.1rem;"><?= htmlspecialchars($appDesc) ?></p>
17
+ <p style="font-size: 0.85rem; color: var(--color-primary); font-weight: 700; margin-top: 4px;">Crafted by <?= htmlspecialchars($author) ?></p>
18
+
19
+ <!-- AJAX Live Form Demo (jQuery / Vanilla Fetch) -->
20
+ <div style="text-align: left; padding: 2rem; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-base); margin-top: 2rem; box-shadow: 0 10px 30px rgba(0,0,0,0.15);">
21
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
22
+ <h3 style="margin: 0;">⚡ Live AJAX + jQuery Demo (No Page Reload)</h3>
23
+ <span style="font-size: 0.75rem; padding: 4px 8px; border-radius: 6px; background: rgba(16, 185, 129, 0.2); color: #10b981; font-weight: bold;">AJAX Ready</span>
24
+ </div>
25
+
26
+ <p style="color: var(--color-text-muted); font-size: 0.9rem;">
27
+ এই Raw PHP আর্কিটেকচারে আপনি নির্দ্বিধায় <strong>jQuery, Axios, Fetch API, Tailwind CSS</strong> বা <strong>Bootstrap 5</strong> যা ইচ্ছা ব্যবহার করতে পারবেন।
28
+ </p>
29
+
30
+ <form id="ajaxUserForm" style="display: grid; grid-template-columns: 1fr 1fr auto; gap: 10px; margin-top: 1rem;">
31
+ <input type="text" id="ajaxName" placeholder="Full Name" required style="padding: 10px; border-radius: 8px; border: 1px solid var(--color-border); background: var(--color-bg); color: var(--color-text);">
32
+ <input type="email" id="ajaxEmail" placeholder="Email Address" required style="padding: 10px; border-radius: 8px; border: 1px solid var(--color-border); background: var(--color-bg); color: var(--color-text);">
33
+ <button type="submit" id="btnSubmit" style="background: var(--color-primary); color: white; border: none; padding: 10px 18px; border-radius: 8px; font-weight: bold; cursor: pointer;">
34
+ Send via AJAX
35
+ </button>
36
+ </form>
37
+ <div id="ajaxResponse" style="margin-top: 10px; font-size: 0.85rem; font-weight: 600;"></div>
38
+ </div>
39
+
40
+ <!-- Dynamic UI Components Section -->
41
+ <div style="text-align: left; padding: 2rem; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-base); margin-top: 2rem;">
42
+ <h4>Included Interactive UI Components:</h4>
43
+ {{UI_COMPONENTS}}
44
+ </div>
45
+ </div>
46
+
47
+ <!-- Live jQuery AJAX Handling Script -->
48
+ <script>
49
+ $(document).ready(function() {
50
+ $('#ajaxUserForm').on('submit', function(e) {
51
+ e.preventDefault();
52
+ const btn = $('#btnSubmit');
53
+ const resp = $('#ajaxResponse');
54
+
55
+ btn.prop('disabled', true).text('Saving...');
56
+ resp.html('<span style="color: var(--color-primary);">Connecting with server...</span>');
57
+
58
+ $.ajax({
59
+ url: '/api/users',
60
+ type: 'POST',
61
+ contentType: 'application/json',
62
+ data: JSON.stringify({
63
+ name: $('#ajaxName').val(),
64
+ email: $('#ajaxEmail').val()
65
+ }),
66
+ success: function(response) {
67
+ resp.html('<span style="color: #10b981;">✓ ' + response.message + '</span>');
68
+ $('#ajaxUserForm')[0].reset();
69
+ },
70
+ error: function(xhr) {
71
+ const err = xhr.responseJSON ? xhr.responseJSON.error : 'Submission failed';
72
+ resp.html('<span style="color: #ef4444;">✗ ' + err + '</span>');
73
+ },
74
+ complete: function() {
75
+ btn.prop('disabled', false).text('Send via AJAX');
76
+ }
77
+ });
78
+ });
79
+ });
80
+ </script>
81
+ <script src="/js/theme.js"></script>
82
+ </body>
83
+ </html>
@@ -0,0 +1,62 @@
1
+ <?php
2
+ namespace App\Config;
3
+
4
+ class Auth {
5
+ public static function init(): void {
6
+ if (session_status() === PHP_SESSION_NONE) {
7
+ session_start();
8
+ }
9
+ }
10
+
11
+ public static function login(array $user): void {
12
+ self::init();
13
+ $_SESSION['user_id'] = $user['id'];
14
+ $_SESSION['user_role'] = $user['role'] ?? 'user';
15
+ $_SESSION['user_name'] = $user['name'];
16
+ $_SESSION['user_email'] = $user['email'];
17
+ }
18
+
19
+ public static function check(): bool {
20
+ self::init();
21
+ return isset($_SESSION['user_id']);
22
+ }
23
+
24
+ public static function user(): ?array {
25
+ self::init();
26
+ if (!self::check()) return null;
27
+ return [
28
+ 'id' => $_SESSION['user_id'],
29
+ 'name' => $_SESSION['user_name'],
30
+ 'email' => $_SESSION['user_email'],
31
+ 'role' => $_SESSION['user_role']
32
+ ];
33
+ }
34
+
35
+ public static function id(): ?int {
36
+ self::init();
37
+ return $_SESSION['user_id'] ?? null;
38
+ }
39
+
40
+ public static function hasRole(string|array $roles): bool {
41
+ self::init();
42
+ if (!self::check()) return false;
43
+ $userRole = $_SESSION['user_role'] ?? 'user';
44
+ if (is_array($roles)) {
45
+ return in_array($userRole, $roles);
46
+ }
47
+ return $userRole === $roles;
48
+ }
49
+
50
+ public static function logout(): void {
51
+ self::init();
52
+ $_SESSION = [];
53
+ if (ini_get("session.use_cookies")) {
54
+ $params = session_get_cookie_params();
55
+ setcookie(session_name(), '', time() - 42000,
56
+ $params["path"], $params["domain"],
57
+ $params["secure"], $params["httponly"]
58
+ );
59
+ }
60
+ session_destroy();
61
+ }
62
+ }
@@ -0,0 +1,100 @@
1
+ <?php
2
+ namespace App\Config;
3
+
4
+ use PDO;
5
+ use PDOException;
6
+
7
+ class Database {
8
+ private static ?PDO $instance = null;
9
+
10
+ /**
11
+ * Get Singleton PDO connection with multi-driver support:
12
+ * - MySQL / MariaDB (utf8mb4)
13
+ * - MSSQL (sqlsrv / dblib)
14
+ * - PostgreSQL (pgsql)
15
+ * - SQLite (zero-config local file)
16
+ */
17
+ public static function getConnection(): PDO {
18
+ if (self::$instance === null) {
19
+ $dbType = strtolower(getenv('DB_CONNECTION') ?: '{{DB_TYPE}}');
20
+ $host = getenv('DB_HOST') ?: '127.0.0.1';
21
+ $dbname = getenv('DB_NAME') ?: getenv('DB_DATABASE') ?: '{{DB_NAME}}';
22
+ $user = getenv('DB_USER') ?: getenv('DB_USERNAME') ?: 'root';
23
+ $pass = getenv('DB_PASS') ?: getenv('DB_PASSWORD') ?: '';
24
+
25
+ $commonOptions = [
26
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
27
+ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
28
+ PDO::ATTR_EMULATE_PREPARES => false,
29
+ ];
30
+
31
+ try {
32
+ switch ($dbType) {
33
+ case 'mssql':
34
+ case 'sqlsrv':
35
+ $port = getenv('DB_PORT') ?: '1433';
36
+ // Checks if sqlsrv driver exists, else fallback to dblib
37
+ if (in_array('sqlsrv', PDO::getAvailableDrivers())) {
38
+ $dsn = "sqlsrv:Server={$host},{$port};Database={$dbname};TrustServerCertificate=true";
39
+ } else {
40
+ $dsn = "dblib:host={$host}:{$port};dbname={$dbname}";
41
+ }
42
+ self::$instance = new PDO($dsn, $user, $pass, $commonOptions);
43
+ break;
44
+
45
+ case 'pgsql':
46
+ case 'postgres':
47
+ $port = getenv('DB_PORT') ?: '5432';
48
+ $dsn = "pgsql:host={$host};port={$port};dbname={$dbname}";
49
+ self::$instance = new PDO($dsn, $user, $pass, $commonOptions);
50
+ break;
51
+
52
+ case 'sqlite':
53
+ $sqlitePath = getenv('DB_PATH') ?: __DIR__ . '/../../database.sqlite';
54
+ if (!file_exists($sqlitePath)) {
55
+ touch($sqlitePath);
56
+ }
57
+ $dsn = "sqlite:{$sqlitePath}";
58
+ self::$instance = new PDO($dsn, null, null, $commonOptions);
59
+ break;
60
+
61
+ case 'mysql':
62
+ case 'mariadb':
63
+ default:
64
+ $port = getenv('DB_PORT') ?: '3306';
65
+ $charset = 'utf8mb4';
66
+ $dsn = "mysql:host={$host};port={$port};dbname={$dbname};charset={$charset}";
67
+ self::$instance = new PDO($dsn, $user, $pass, $commonOptions);
68
+ break;
69
+ }
70
+ } catch (PDOException $e) {
71
+ http_response_code(500);
72
+ header('Content-Type: application/json');
73
+ echo json_encode([
74
+ 'success' => false,
75
+ 'error' => "Database Connection Failed [Engine: {$dbType}]",
76
+ 'message' => $e->getMessage()
77
+ ]);
78
+ exit;
79
+ }
80
+ }
81
+ return self::$instance;
82
+ }
83
+
84
+ /**
85
+ * Helper to run parameterized queries safely
86
+ */
87
+ public static function query(string $sql, array $params = []): array {
88
+ $stmt = self::getConnection()->prepare($sql);
89
+ $stmt->execute($params);
90
+ return $stmt->fetchAll();
91
+ }
92
+
93
+ /**
94
+ * Helper for INSERT / UPDATE / DELETE
95
+ */
96
+ public static function execute(string $sql, array $params = []): bool {
97
+ $stmt = self::getConnection()->prepare($sql);
98
+ return $stmt->execute($params);
99
+ }
100
+ }