From f7302e3741cc2fc858b791db1b78ed6be7a5a204 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 14:52:41 +0300 Subject: [PATCH 01/16] fix(deploy): strip frankenphp capabilities and move to port 8080 for render --- Dockerfile | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 33ebb3e..71823e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM dunglas/frankenphp:1.4-php8.4-alpine ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser \ COMPOSER_ALLOW_SUPERUSER=1 \ - SERVER_NAME=:80 \ + SERVER_NAME=:8080 \ PUBLIC_ROOT=/app/public # Install system dependencies @@ -25,7 +25,8 @@ RUN apk add --no-cache \ postgresql-dev \ git \ unzip \ - bash + bash \ + libcap # Install PHP extensions RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ @@ -40,7 +41,9 @@ RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \ && pecl install redis \ && docker-php-ext-enable redis \ - && apk del .build-deps + && apk del .build-deps \ + && setcap -r /usr/local/bin/frankenphp \ + && apk del libcap # Set working directory WORKDIR /app @@ -75,7 +78,7 @@ RUN { \ echo 'opcache.enable_cli=1'; \ } > /usr/local/etc/php/conf.d/opcache-recommended.ini -# Expose port 80 -EXPOSE 80 +# Expose port 8080 +EXPOSE 8080 # The entrypoint is already set to frankenphp in the base image From b498370b69a87bbe5c127b78a49c8efac937921a Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 15:51:35 +0300 Subject: [PATCH 02/16] chore: update build files - Add CaddyFile, update Dockerfile --- Caddyfile | 9 +++++++++ Dockerfile | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 Caddyfile diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..8305f90 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,9 @@ +:80 { + root * /app/public + + encode gzip + + php_fastcgi 127.0.0.1:9000 + + file_server +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 71823e5..c5814a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM dunglas/frankenphp:1.4-php8.4-alpine ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser \ COMPOSER_ALLOW_SUPERUSER=1 \ - SERVER_NAME=:8080 \ + SERVER_NAME=:80 \ PUBLIC_ROOT=/app/public # Install system dependencies @@ -78,7 +78,7 @@ RUN { \ echo 'opcache.enable_cli=1'; \ } > /usr/local/etc/php/conf.d/opcache-recommended.ini -# Expose port 8080 -EXPOSE 8080 +# Expose port 80 +EXPOSE 80 # The entrypoint is already set to frankenphp in the base image From 2ac8c01920b36f52c72c9c884a993fb36395c643 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 15:58:26 +0300 Subject: [PATCH 03/16] feat: copy custom Caddyfile configuration into Docker image --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index c5814a9..3985231 100644 --- a/Dockerfile +++ b/Dockerfile @@ -78,6 +78,9 @@ RUN { \ echo 'opcache.enable_cli=1'; \ } > /usr/local/etc/php/conf.d/opcache-recommended.ini +# Copy custom Caddyfile and set permissions +COPY Caddyfile /etc/caddy/Caddyfile + # Expose port 80 EXPOSE 80 From 333ea1fab45b67bebbfd5e4d8ce35267edfb54a4 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 16:28:21 +0300 Subject: [PATCH 04/16] chore: update Caddyfile --- Caddyfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Caddyfile b/Caddyfile index 8305f90..b5245d8 100644 --- a/Caddyfile +++ b/Caddyfile @@ -1,9 +1,8 @@ :80 { root * /app/public - encode gzip - php_fastcgi 127.0.0.1:9000 + php_server file_server } \ No newline at end of file From 2b0667595aa4d826c50b84cef63c5248a1b66299 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 16:35:26 +0300 Subject: [PATCH 05/16] chore: update Dockerfile - Explicilty define CMD and update SERVER_NAME --- Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3985231..bb5ee4f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM dunglas/frankenphp:1.4-php8.4-alpine ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser \ COMPOSER_ALLOW_SUPERUSER=1 \ - SERVER_NAME=:80 \ + SERVER_NAME=0.0.0.0:80 \ PUBLIC_ROOT=/app/public # Install system dependencies @@ -81,7 +81,6 @@ RUN { \ # Copy custom Caddyfile and set permissions COPY Caddyfile /etc/caddy/Caddyfile -# Expose port 80 EXPOSE 80 -# The entrypoint is already set to frankenphp in the base image +CMD ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile"] \ No newline at end of file From 1dd9fbbada919ac87281ea9a6c9ddd2b95c456b5 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 16:58:44 +0300 Subject: [PATCH 06/16] chore: update config files --- Caddyfile | 16 +++++++++++++--- Dockerfile | 12 +++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Caddyfile b/Caddyfile index b5245d8..067a8db 100644 --- a/Caddyfile +++ b/Caddyfile @@ -1,8 +1,18 @@ -:80 { +{ + # Enable the FrankenPHP module globally + frankenphp + # Disable the admin API to prevent host conflicts on Render + admin off +} + +# Listen on port 8080 (unprivileged port for Render) +:8080 { root * /app/public encode gzip - + + # Enable the FrankenPHP server php_server - + + # Handle static files file_server } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index bb5ee4f..ecc6dcf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,9 @@ FROM dunglas/frankenphp:1.4-php8.4-alpine ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser \ COMPOSER_ALLOW_SUPERUSER=1 \ - SERVER_NAME=0.0.0.0:80 \ - PUBLIC_ROOT=/app/public + SERVER_NAME=:8080 \ + PUBLIC_ROOT=/app/public \ + LOG_CHANNEL=stderr # Install system dependencies RUN apk add --no-cache \ @@ -78,9 +79,10 @@ RUN { \ echo 'opcache.enable_cli=1'; \ } > /usr/local/etc/php/conf.d/opcache-recommended.ini -# Copy custom Caddyfile and set permissions +# Copy custom Caddyfile COPY Caddyfile /etc/caddy/Caddyfile -EXPOSE 80 +# Expose port 8080 +EXPOSE 8080 -CMD ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile"] \ No newline at end of file +# The entrypoint is already set to frankenphp in the base image \ No newline at end of file From 82eeb66f4334a4800af63cb800931fb59f99c1e1 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 17:10:20 +0300 Subject: [PATCH 07/16] chore: configure trustProxies for render environment --- bootstrap/app.php | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap/app.php b/bootstrap/app.php index f8cd7be..ce89ddc 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -13,6 +13,7 @@ health: '/up', ) ->withMiddleware(function (Middleware $middleware) { + $middleware->trustProxies(at: '*'); $middleware->append([ \App\Http\Middleware\SecurityHeaders::class, \App\Http\Middleware\CheckIfActive::class, From 5235f32baa995d128911b0f96cea69f151536aeb Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 17:22:39 +0300 Subject: [PATCH 08/16] chore: update browser list --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec1890e..e32ffd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1295,9 +1295,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001695", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz", - "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==", + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", "dev": true, "funding": [ { From 02f65fe2567adb2672e7ec1ecc0c18d90e92db29 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 17:24:38 +0300 Subject: [PATCH 09/16] feat(deploy): implement automated migrations via entrypoint script for render free tier --- Dockerfile | 7 ++++++- entrypoint.sh | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 entrypoint.sh diff --git a/Dockerfile b/Dockerfile index ecc6dcf..f87b121 100644 --- a/Dockerfile +++ b/Dockerfile @@ -82,7 +82,12 @@ RUN { \ # Copy custom Caddyfile COPY Caddyfile /etc/caddy/Caddyfile +# Copy entrypoint script and set permissions +COPY entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + # Expose port 8080 EXPOSE 8080 -# The entrypoint is already set to frankenphp in the base image \ No newline at end of file +# Use the entrypoint script to run migrations and start the server +CMD ["/usr/local/bin/entrypoint.sh"] diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..14e5c22 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e + +# Run migrations automatically on startup +echo "[ENTRYPOINT] Running migrations..." +php artisan migrate --force + +# Execute the main container command (FrankenPHP) +echo "[ENTRYPOINT] Starting FrankenPHP..." +exec frankenphp run --config /etc/caddy/Caddyfile From ffaec212eeac74504db5a3c2ee0d48525cdd4da0 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 17:29:52 +0300 Subject: [PATCH 10/16] fix: remove redundant style --- resources/views/home.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php index fe36fcd..8f60d62 100644 --- a/resources/views/home.blade.php +++ b/resources/views/home.blade.php @@ -26,7 +26,7 @@

StrathPort

+ class="max-w-2xl mb-6 font-light text-gray-800 dark:text-gray-500 lg:mb-8 md:text-lg lg:text-xl"> Sign up now to take a step towards a smoother, safer, journey!

From 3800546aa009a9fbed5c1418b9d2efeecfd20632 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 21:53:56 +0300 Subject: [PATCH 11/16] feat: ensure idempotency of role permission seeding --- database/seeders/RolePermissionSeeder.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/database/seeders/RolePermissionSeeder.php b/database/seeders/RolePermissionSeeder.php index e1d497d..e8691ab 100644 --- a/database/seeders/RolePermissionSeeder.php +++ b/database/seeders/RolePermissionSeeder.php @@ -6,6 +6,7 @@ use Illuminate\Database\Seeder; use Spatie\Permission\Models\Permission; use Spatie\Permission\Models\Role; +use Spatie\Permission\PermissionRegistrar; class RolePermissionSeeder extends Seeder { @@ -14,6 +15,9 @@ class RolePermissionSeeder extends Seeder */ public function run(): void { + // Reset cache + app(PermissionRegistrar::class)->forgetCachedPermissions(); + // Create permissions $permissions = [ 'view student dashboard', @@ -33,7 +37,7 @@ public function run(): void ]; foreach ($permissions as $permission) { - Permission::create(['name' => $permission]); + Permission::firstOrCreate(['name' => $permission]); } /* Create roles and assign permissions */ @@ -74,8 +78,10 @@ public function run(): void ]; foreach ($rolePermissions as $roleName => $permissions) { - $role = Role::create(['name' => $roleName]); - $role->givePermissionTo($permissions); + $role = Role::firstOrCreate(['name' => $roleName]); + + // Sync permissions + $role->syncPermissions($permissions); } From eb26ff0aa855c5d0ed2c179e000113698e4d05e0 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 21:54:23 +0300 Subject: [PATCH 12/16] chore: update entrypoint - Add command to seed roles + permissions --- entrypoint.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/entrypoint.sh b/entrypoint.sh index 14e5c22..7f820c4 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -5,6 +5,10 @@ set -e echo "[ENTRYPOINT] Running migrations..." php artisan migrate --force +# Run RolePermissionSeeder +echo "[ENTRYPOINT] Running RolePermissionSeeder..." +php artisan db:seed --class=RolePermissionSeeder --force + # Execute the main container command (FrankenPHP) echo "[ENTRYPOINT] Starting FrankenPHP..." exec frankenphp run --config /etc/caddy/Caddyfile From b7433fc60410dc20290cc14a9d0d3e2498a8f00b Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 21:57:13 +0300 Subject: [PATCH 13/16] chore: update entrypoint - Add command to seed users --- entrypoint.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/entrypoint.sh b/entrypoint.sh index 7f820c4..9a0cd28 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -9,6 +9,10 @@ php artisan migrate --force echo "[ENTRYPOINT] Running RolePermissionSeeder..." php artisan db:seed --class=RolePermissionSeeder --force +# Run UserSeeder +echo "[ENTRYPOINT] Running UserSeeder..." +php artisan db:seed --class=UserSeeder --force + # Execute the main container command (FrankenPHP) echo "[ENTRYPOINT] Starting FrankenPHP..." exec frankenphp run --config /etc/caddy/Caddyfile From a100b241a00b9864cc44d285ce26f880b8049626 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 22:23:22 +0300 Subject: [PATCH 14/16] fix: ensure initial users are created idempotently --- database/seeders/UserSeeder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index e035352..9049cb9 100644 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -30,7 +30,7 @@ public function run(): void foreach ($users as $userData) { $password = Str::random(12); - $user = User::create([ + $user = User::firstOrCreate([ 'name' => $userData['name'], 'email' => $userData['email'], 'password' => bcrypt($password), From 44988a3d641a1c408d454b3348f70e92a37a9b03 Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 23:07:59 +0300 Subject: [PATCH 15/16] refactor: use email as the unique identifier --- database/seeders/UserSeeder.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index 9049cb9..c8536cb 100644 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -30,14 +30,16 @@ public function run(): void foreach ($users as $userData) { $password = Str::random(12); - $user = User::firstOrCreate([ - 'name' => $userData['name'], - 'email' => $userData['email'], - 'password' => bcrypt($password), - 'phone' => '+254712345678', - 'account_status' => 'active', - 'email_verified_at' => now(), - ]); + $user = User::firstOrCreate( + ['email' => $userData['email']], + [ + 'name' => $userData['name'], + 'password' => bcrypt($password), + 'phone' => '+254700000000', + 'account_status' => 'active', + 'email_verified_at' => now(), + ] + ); if ($userData['role']) { $user->assignRole($userData['role']); From 9f6e23c44f1cb7db07fc3b388bc2a632b60a679b Mon Sep 17 00:00:00 2001 From: Fidelisaboke Date: Tue, 14 Apr 2026 23:27:45 +0300 Subject: [PATCH 16/16] fix: prevent division by zero and handle null values when calculating dashboard analytics --- app/View/Components/AdminDashboard.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/View/Components/AdminDashboard.php b/app/View/Components/AdminDashboard.php index c69f8af..5df31c7 100644 --- a/app/View/Components/AdminDashboard.php +++ b/app/View/Components/AdminDashboard.php @@ -40,16 +40,23 @@ public function __construct() $this->totalcarpoolVehicles = CarpoolVehicle::count('id'); // Request approval rate - $this->requestApprovalRate = number_format((TransportRequest::where('status', 'Approved')->count() / $this->totalTransportRequests) * 100, 2); + $total = $this->totalTransportRequests; + $this->requestApprovalRate = $total > 0 + ? number_format((TransportRequest::where('status', 'Approved')->count() / $total) * 100, 2) + : 0; // Peak request month - $this->peakRequestMonth = TransportRequest::selectRaw('EXTRACT(MONTH FROM event_date) as month, count(*) as requests') + $peak = TransportRequest::selectRaw('EXTRACT(MONTH FROM event_date) as month, count(*) as requests') ->groupBy('month') ->orderBy('requests', 'desc') ->first(); // Return the month name - $this->peakRequestMonth = date('F', mktime(0, 0, 0, $this->peakRequestMonth->month, 10)); + if ($peak && $peak->month) { + $this->peakRequestMonth = date('F', mktime(0, 0, 0, $peak->month, 10)); + } else { + $this->peakRequestMonth = 'N/A'; + } } /**