From b4ac5451bb079bcef4384679cc6e95247aef0460 Mon Sep 17 00:00:00 2001 From: Vasyka Date: Fri, 8 May 2026 10:41:14 +0000 Subject: [PATCH] Persistent storage volume + remove debug route + validate logo file exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Coolify persistent volume mounted at /app/storage/app (covers public uploads, private files, backups). Configured via API: POST /api/v1/applications/{uuid}/storages with type=persistent - getLogoUrl() / getFaviconUrl() now validate file_exists($m->getPath()) before returning URL — guards against stale DB rows from pre-volume era - Removed /debug-storage diagnostic route (used to find the symlink+volume bug) --- app/Models/Central/Company.php | 10 ++++-- routes/web.php | 56 ---------------------------------- 2 files changed, 8 insertions(+), 58 deletions(-) diff --git a/app/Models/Central/Company.php b/app/Models/Central/Company.php index f036c4c..7840358 100644 --- a/app/Models/Central/Company.php +++ b/app/Models/Central/Company.php @@ -98,12 +98,18 @@ class Company extends BaseTenant implements HasMedia public function getLogoUrl(): ?string { $m = $this->getFirstMedia('logo'); - return $m ? $m->getUrl() : null; + if (! $m) return null; + // Validate file actually exists on disk (storage may be ephemeral + // and DB row may point to lost file from previous deploy). + if (! @file_exists($m->getPath())) return null; + return $m->getUrl(); } public function getFaviconUrl(): ?string { $m = $this->getFirstMedia('favicon'); - return $m ? $m->getUrl() : null; + if (! $m) return null; + if (! @file_exists($m->getPath())) return null; + return $m->getUrl(); } } diff --git a/routes/web.php b/routes/web.php index 0722ab7..3ec033e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -46,62 +46,6 @@ Route::post('/payments/paypal/webhook', [\App\Http\Controllers\PaymentController Route::post('/payments/paynet/webhook', [\App\Http\Controllers\PaymentController::class, 'paynetWebhook']) ->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]); -// DEBUG — verifică starea storage symlink + media library. -// TODO: remove after debug. -Route::get('/debug-storage', function () { - $publicStoragePath = public_path('storage'); - $storageAppPublic = storage_path('app/public'); - - // Try to write a test file - if (! is_dir($storageAppPublic)) @mkdir($storageAppPublic, 0775, true); - @file_put_contents($storageAppPublic . '/test.txt', 'OK ' . now()->toIso8601String()); - - $latestMedia = \DB::table('media')->latest('id')->first(); - - // List contents of /app/storage/app/public - $contents = []; - if (is_dir($storageAppPublic)) { - foreach (scandir($storageAppPublic) as $item) { - if (in_array($item, ['.', '..'])) continue; - $full = $storageAppPublic . '/' . $item; - if (is_dir($full)) { - $sub = array_values(array_diff(scandir($full), ['.', '..'])); - $contents[$item . '/'] = $sub; - } else { - $contents[] = $item . ' (' . filesize($full) . 'b)'; - } - } - } - - return response()->json([ - 'public_storage' => [ - 'path' => $publicStoragePath, - 'is_link' => is_link($publicStoragePath), - 'exists' => file_exists($publicStoragePath), - 'target' => is_link($publicStoragePath) ? readlink($publicStoragePath) : null, - 'is_dir' => is_dir($publicStoragePath), - ], - 'storage_app_public' => [ - 'path' => $storageAppPublic, - 'exists' => is_dir($storageAppPublic), - 'test_file_written' => file_exists($storageAppPublic . '/test.txt'), - 'test_file_url' => url('/storage/test.txt'), - ], - 'latest_media' => $latestMedia ? [ - 'id' => $latestMedia->id, - 'model' => $latestMedia->model_type . '#' . $latestMedia->model_id, - 'collection' => $latestMedia->collection_name, - 'name' => $latestMedia->file_name, - 'disk' => $latestMedia->disk, - 'expected_path' => $storageAppPublic . '/' . $latestMedia->id . '/' . $latestMedia->file_name, - 'file_exists' => file_exists($storageAppPublic . '/' . $latestMedia->id . '/' . $latestMedia->file_name), - ] : null, - 'media_disk_config' => config('media-library.disk_name'), - 'app_url' => config('app.url'), - 'storage_listing' => $contents, - ]); -}); - // Stub `login` route — needed because Laravel's auth middleware tries to // route('login') when redirecting unauthenticated requests. We don't have a // global /login (panels use /admin/login and /app/login), so stub it.