--- .env
--- school_api_orig/school_api/.env	2026-06-04 07:50:20.000000000 +0000
+++ school_api_work/school_api/.env	2026-06-04 17:35:04.127545553 +0000
@@ -1,9 +1,9 @@
 APP_NAME=Alrahma_API
-APP_ENV=local
-APP_KEY=base64:RfIZKqgXC9seghl2Jqs2MgLh1X1Z7APRsnhUK8CgWx8=
-APP_DEBUG=true
+APP_ENV=production
+APP_KEY=base64:CHANGE_ME_GENERATE_WITH_php_artisan_key_generate
+APP_DEBUG=false
 APP_TIMEZONE=America/New_York
-APP_URL=http://localhost:8080
+APP_URL=https://example.com
 
 APP_LOCALE=en
 APP_FALLBACK_LOCALE=en
@@ -22,18 +22,21 @@
 DB_HOST=127.0.0.1
 DB_PORT=3306
 DB_DATABASE=school_api
-DB_USERNAME=root
-DB_PASSWORD=root
-APP_URL=http://127.0.0.1:8000
+DB_USERNAME=school_api_user
+DB_PASSWORD=CHANGE_ME_DB_PASSWORD
+APP_URL=https://example.com
 
 # ----------------------------
 # SESSION
 # ----------------------------
 SESSION_DRIVER=file
 SESSION_LIFETIME=120
-SESSION_ENCRYPT=false
+SESSION_ENCRYPT=true
 SESSION_PATH=/
 SESSION_DOMAIN=null
+SESSION_SECURE_COOKIE=true
+SESSION_HTTP_ONLY=true
+SESSION_SAME_SITE=strict
 
 # ----------------------------
 # CACHE & QUEUE
@@ -56,10 +59,10 @@
 MAIL_PROFILE_DEFAULT=default
 MAIL_DEFAULT_HOST=smtp.gmail.com
 MAIL_DEFAULT_PORT=587
-MAIL_DEFAULT_USER=alrahma.sunday.school@gmail.com
-MAIL_DEFAULT_PASS="psnp emdq dykw ypul"
+MAIL_DEFAULT_USER=CHANGE_ME_SMTP_USER
+MAIL_DEFAULT_PASS=CHANGE_ME_SMTP_PASSWORD
 MAIL_DEFAULT_ENCRYPTION=tls
-MAIL_DEFAULT_FROM_EMAIL="alrahma.sunday.school@gmail.com"
+MAIL_DEFAULT_FROM_EMAIL="no-reply@example.com"
 MAIL_DEFAULT_FROM_NAME="Alrahma API"
 MAIL_DEFAULT_REPLY_TO="alrahma.isgl@gmail.com"
 MAIL_DEFAULT_REPLY_TO_NAME="Al Rahma Sunday School"
@@ -102,7 +105,7 @@
 # ----------------------------
 # JWT
 # ----------------------------
-JWT_SECRET=Uj8rGnYcXMgeRc5qCIn9Wn03tYo1pCsBz1Biou8T9zWtaNxBYi3P4NP5vuFiXHmd
+JWT_SECRET=CHANGE_ME_GENERATE_WITH_php_artisan_jwt_secret
 JWT_ALGO=HS256
 JWT_TTL=60
 JWT_REFRESH_TTL=20160
--- routes/web.php
--- school_api_orig/school_api/routes/web.php	2026-05-29 00:28:37.000000000 +0000
+++ school_api_work/school_api/routes/web.php	2026-06-04 17:35:04.129001398 +0000
@@ -61,7 +61,7 @@
 Route::middleware('web')->group(function () {
     Route::get('login', [AuthSessionController::class, 'loginMask'])->name('login');
     Route::post('user/login', [AuthSessionController::class, 'login'])->name('auth.session.login');
-    Route::get('logout', [AuthSessionController::class, 'logout'])->name('auth.session.logout');
+    Route::post('logout', [AuthSessionController::class, 'logout'])->name('auth.session.logout');
     Route::get('select-role', [AuthSessionController::class, 'selectRole'])->name('auth.session.select-role');
     Route::post('set-role', [AuthSessionController::class, 'setRole'])->name('auth.session.set-role');
 
--- routes/api.php
--- school_api_orig/school_api/routes/api.php	2026-06-04 17:05:37.000000000 +0000
+++ school_api_work/school_api/routes/api.php	2026-06-04 17:35:04.130570862 +0000
@@ -126,8 +126,8 @@
 use App\Http\Controllers\Api\System\AccessDeniedController;
 use App\Http\Controllers\Api\Certificates\CertificateController;
 // Public auth aliases without the `/v1` prefix.
-Route::post('login', [AuthController::class, 'login']);
-Route::post('register', [RegisterController::class, 'store']);
+Route::post('login', [AuthController::class, 'login'])->middleware('throttle:10,1');
+Route::post('register', [RegisterController::class, 'store'])->middleware('throttle:5,1');
 
 /*
 | LanguageTool proxy for legacy and current clients.
@@ -160,12 +160,15 @@
 });
 
 Route::get('confirm_authorized_user', [AuthorizedUserInviteController::class, 'confirm'])
+    ->middleware('throttle:20,1')
     ->name('api.invite.confirm');
 Route::get('set_authorized_user_password/{authorizedUserId}', [AuthorizedUserInviteController::class, 'setPasswordForm'])
     ->whereNumber('authorizedUserId')
+    ->middleware('throttle:20,1')
     ->name('api.invite.set-password-form');
 Route::post('set_authorized_user_password/{authorizedUserId}', [AuthorizedUserInviteController::class, 'savePassword'])
     ->whereNumber('authorizedUserId')
+    ->middleware('throttle:10,1')
     ->name('api.invite.set-password');
 
 /*
@@ -184,13 +187,13 @@
 
 Route::prefix('v1')->group(function () {
     // Public auth aliases without the `/auth` prefix.
-    Route::post('login', [AuthController::class, 'login']);
-    Route::post('register', [RegisterController::class, 'store']);
+    Route::post('login', [AuthController::class, 'login'])->middleware('throttle:10,1');
+    Route::post('register', [RegisterController::class, 'store'])->middleware('throttle:5,1');
 
     Route::prefix('auth')->group(function () {
-        Route::get('register/captcha', [RegisterController::class, 'captcha']);
-        Route::post('register', [RegisterController::class, 'store']);
-        Route::post('login', [AuthController::class, 'login']);
+        Route::get('register/captcha', [RegisterController::class, 'captcha'])->middleware('throttle:30,1');
+        Route::post('register', [RegisterController::class, 'store'])->middleware('throttle:5,1');
+        Route::post('login', [AuthController::class, 'login'])->middleware('throttle:10,1');
         Route::post('refresh', [AuthController::class, 'refresh'])->middleware('jwt.auth');
         Route::post('logout', [AuthController::class, 'logout'])->middleware('auth:api');
         Route::get('me', [AuthController::class, 'me'])->middleware('auth:api');
@@ -208,7 +211,7 @@
         Route::post('contact', [PageController::class, 'submitContact']);
     });
 
-    Route::post('contact', [SupportContactController::class, 'send']);
+    Route::post('contact', [SupportContactController::class, 'send'])->middleware('throttle:5,1');
 
     /*
     | Badge scan kiosk (public, throttled). Logs: authenticated staff.
--- bootstrap/app.php
--- school_api_orig/school_api/bootstrap/app.php	2026-05-29 03:38:30.000000000 +0000
+++ school_api_work/school_api/bootstrap/app.php	2026-06-04 17:35:04.128252803 +0000
@@ -15,6 +15,8 @@
         health: '/up',
     )
     ->withMiddleware(function (Middleware $middleware): void {
+        $middleware->append(\App\Http\Middleware\SecurityHeaders::class);
+
         $middleware->alias([
             // JWT auth
             'jwt.auth' => \PHPOpenSourceSaver\JWTAuth\Http\Middleware\Authenticate::class,
--- app/Http/Middleware/SecurityHeaders.php
--- app/Services/Files/FileServeService.php
--- school_api_orig/school_api/app/Services/Files/FileServeService.php	2026-05-29 00:28:37.000000000 +0000
+++ school_api_work/school_api/app/Services/Files/FileServeService.php	2026-06-04 17:35:04.131136361 +0000
@@ -39,13 +39,10 @@
             'Content-Length' => (string) $meta['size'],
             'ETag' => $meta['etag'],
             'Last-Modified' => $meta['last_modified'],
-            'Cache-Control' => 'public, max-age=86400',
+            'Cache-Control' => 'private, max-age=300',
+            'X-Content-Type-Options' => 'nosniff',
         ];
 
-        if ($nosniff) {
-            $headers['X-Content-Type-Options'] = 'nosniff';
-        }
-
         return response(file_get_contents($meta['path']), 200, $headers);
     }
 
--- app/Services/Events/EventManagementService.php
--- school_api_orig/school_api/app/Services/Events/EventManagementService.php	2026-05-29 00:28:37.000000000 +0000
+++ school_api_work/school_api/app/Services/Events/EventManagementService.php	2026-06-04 17:35:04.131625457 +0000
@@ -103,12 +103,28 @@
             return null;
         }
 
+        $allowed = [
+            'image/jpeg' => 'jpg',
+            'image/png' => 'png',
+            'image/webp' => 'webp',
+            'application/pdf' => 'pdf',
+        ];
+
+        $mime = strtolower((string) $file->getMimeType());
+        if (! isset($allowed[$mime])) {
+            throw new \InvalidArgumentException('Unsupported flyer file type.');
+        }
+
+        if ((int) $file->getSize() > 5 * 1024 * 1024) {
+            throw new \InvalidArgumentException('Flyer file too large. Max 5MB.');
+        }
+
         $dir = public_path('uploads/event_flyers');
         if (!File::exists($dir)) {
             File::makeDirectory($dir, 0755, true);
         }
 
-        $name = $file->hashName();
+        $name = bin2hex(random_bytes(16)) . '.' . $allowed[$mime];
         $file->move($dir, $name);
 
         return 'event_flyers/' . $name;
--- app/Services/Expenses/ExpenseReceiptService.php
--- school_api_orig/school_api/app/Services/Expenses/ExpenseReceiptService.php	2026-05-29 00:28:37.000000000 +0000
+++ school_api_work/school_api/app/Services/Expenses/ExpenseReceiptService.php	2026-06-04 17:35:04.132035612 +0000
@@ -14,8 +14,30 @@
 
     public function storeReceipt(UploadedFile $file): string
     {
-        $stored = $file->store('receipts');
-        return basename($stored);
+        if (! $file->isValid()) {
+            throw new \InvalidArgumentException('Invalid receipt upload.');
+        }
+
+        $allowed = [
+            'image/jpeg' => 'jpg',
+            'image/png' => 'png',
+            'image/webp' => 'webp',
+            'application/pdf' => 'pdf',
+        ];
+
+        $mime = strtolower((string) $file->getMimeType());
+        if (! isset($allowed[$mime])) {
+            throw new \InvalidArgumentException('Unsupported receipt file type.');
+        }
+
+        if ((int) $file->getSize() > 5 * 1024 * 1024) {
+            throw new \InvalidArgumentException('Receipt file too large. Max 5MB.');
+        }
+
+        $filename = bin2hex(random_bytes(16)) . '.' . $allowed[$mime];
+        $file->storeAs('receipts', $filename);
+
+        return $filename;
     }
 
     public function receiptUrl(?string $filename): ?string
--- app/Services/BroadcastEmail/BroadcastEmailImageService.php
--- school_api_orig/school_api/app/Services/BroadcastEmail/BroadcastEmailImageService.php	2026-05-29 00:28:37.000000000 +0000
+++ school_api_work/school_api/app/Services/BroadcastEmail/BroadcastEmailImageService.php	2026-06-04 17:35:04.132596226 +0000
@@ -17,6 +17,14 @@
 
     public function store(UploadedFile $file): array
     {
+        if (! $file->isValid()) {
+            return [
+                'ok' => false,
+                'status' => 400,
+                'error' => 'Invalid upload',
+            ];
+        }
+
         $mime = strtolower((string) $file->getMimeType());
         if (!isset($this->allowedTypes[$mime])) {
             return [
@@ -40,7 +48,7 @@
         }
 
         $ext = $this->allowedTypes[$mime];
-        $newName = uniqid('em_', true) . '.' . $ext;
+        $newName = 'em_' . bin2hex(random_bytes(16)) . '.' . $ext;
         $file->move($targetDir, $newName);
 
         return [
--- app/Services/PrintRequests/PrintRequestsPortalService.php
--- school_api_orig/school_api/app/Services/PrintRequests/PrintRequestsPortalService.php	2026-06-04 06:36:56.000000000 +0000
+++ school_api_work/school_api/app/Services/PrintRequests/PrintRequestsPortalService.php	2026-06-04 17:35:04.133321294 +0000
@@ -387,7 +387,7 @@
     public function storeTeacherUpload(array $data, UploadedFile $file, int $teacherId): PrintRequest
     {
         $this->ensureStorageDirectoryExists();
-        $ext = $file->getClientOriginalExtension();
+        $ext = $this->safeExtensionForUpload($file);
         $stored = Str::uuid()->toString().($ext !== '' ? '.'.$ext : '');
         $file->move($this->storageDirectory(), $stored);
 
@@ -432,7 +432,7 @@
                     }
                 }
             }
-            $ext = $newFile->getClientOriginalExtension();
+            $ext = $this->safeExtensionForUpload($newFile);
             $stored = Str::uuid()->toString().($ext !== '' ? '.'.$ext : '');
             $newFile->move($this->storageDirectory(), $stored);
             $update['file_path'] = $stored;
@@ -445,6 +445,29 @@
         return $request->fresh();
     }
 
+    private function safeExtensionForUpload(UploadedFile $file): string
+    {
+        $allowed = [
+            'application/pdf' => 'pdf',
+            'image/jpeg' => 'jpg',
+            'image/png' => 'png',
+            'text/plain' => 'txt',
+            'application/msword' => 'doc',
+            'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
+        ];
+
+        $mime = strtolower((string) $file->getMimeType());
+        if (! isset($allowed[$mime])) {
+            throw new \InvalidArgumentException('Unsupported upload type.');
+        }
+
+        if ((int) $file->getSize() > 5 * 1024 * 1024) {
+            throw new \InvalidArgumentException('Uploaded file too large. Max 5MB.');
+        }
+
+        return $allowed[$mime];
+    }
+
     public function applyAdminStatus(PrintRequest $request, string $newStatus, int $adminUserId): PrintRequest
     {
         $current = (string) $request->status;
--- app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php
--- school_api_orig/school_api/app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php	2026-05-29 00:28:37.000000000 +0000
+++ school_api_work/school_api/app/Http/Controllers/Api/PrintRequests/PrintRequestsController.php	2026-06-04 17:35:04.133827253 +0000
@@ -47,7 +47,7 @@
         }
 
         $validator = Validator::make($request->all(), [
-            'file' => ['required', 'file', 'max:5120', 'mimes:pdf,jpg,jpeg,png,doc,docx,txt'],
+            'file' => ['required', 'file', 'max:5120', 'mimes:pdf,jpg,jpeg,png,doc,docx,txt', 'mimetypes:application/pdf,image/jpeg,image/png,text/plain,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
             'page_selection' => ['nullable', 'string', 'regex:/^\s*\d+(?:\s*-\s*\d+)?(?:\s*,\s*\d+(?:\s*-\s*\d+)?)*\s*$/'],
             'num_copies' => ['required', 'integer', 'min:1'],
             'required_by' => ['required', 'date'],
@@ -97,7 +97,7 @@
         ];
 
         if ($request->hasFile('file') && $request->file('file')->isValid()) {
-            $rules['file'] = ['required', 'file', 'max:5120', 'mimes:pdf,jpg,jpeg,png,doc,docx,txt'];
+            $rules['file'] = ['required', 'file', 'max:5120', 'mimes:pdf,jpg,jpeg,png,doc,docx,txt', 'mimetypes:application/pdf,image/jpeg,image/png,text/plain,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
         }
 
         $validator = Validator::make($request->all(), $rules);
--- app/Models/User.php
--- test.sql
--- school_api_orig/school_api/test.sql	2026-05-29 00:27:51.000000000 +0000
+++ school_api_work/school_api/test.sql	2026-06-04 17:35:52.923658533 +0000
@@ -479,15 +479,15 @@
 (29, 'total_semester2_days', '13'),
 (30, 'delete_email_notify', 'support@alrahmaisgl.org, melabidi@alrahmaisgl.org'),
 (31, 'fall_semester_start', '2025-09-21'),
-(32, 'sandbox_secret_paypal', 'Ar0Br3ZhBukQwwdSCxIcSveiu70-Ekt-qqF0nSyYNr3eRAYQKcWTTlhCAKncZiYXmBoPeo4IceV6FjT'),
+(32, 'sandbox_secret_paypal', 'CHANGE_ME_SANDBOX_SECRET_PAYPAL'),
 (33, 'sandbox_verifylink_paypal', 'https://api-m.sandbox.paypal.com/v1/notifications/verify-webhook-signature'),
 (34, 'sandbox_tokenurl_paypal', 'https://api-m.sandbox.paypal.com/v1/oauth2/token'),
-(35, 'sandbox_clientid_paypal', 'AYsiOekZUvrjgx9C5c554ZeSQ4W6yd0ZX-OHE93_D0fWoa4YXrMmroEeLiAjjdCKkELH8EVZR_yGMLPS'),
-(36, 'sandbox_webhookid_paypal', '0EU27043LC060650D'),
+(35, 'sandbox_clientid_paypal', 'CHANGE_ME_SANDBOX_CLIENTID_PAYPAL'),
+(36, 'sandbox_webhookid_paypal', 'CHANGE_ME_SANDBOX_WEBHOOKID_PAYPAL'),
 (37, 'production_verifylink_paypal', 'https://api-m.paypal.com/v1/notifications/verify-webhook-signature'),
-(38, 'production_webhookid_paypal', '0H5876426L0092829'),
-(39, 'production_secret_paypal', 'KKvmE-0cvwx8rEHnEcFaAvn1Rlc3cy07IGIjqGGPR8EqxABbmPodM_JrjRQq2SF2903A4q0DBjjUWai'),
-(40, 'production_clientid_paypal', 'AQhCgmypaitgLgretMqNrh_7mEG5fAmwCECxCxevuLDQfsQVwECFyQOU50byzPzFrwd0cVVD8r2lujIB'),
+(38, 'production_webhookid_paypal', 'CHANGE_ME_PRODUCTION_WEBHOOKID_PAYPAL'),
+(39, 'production_secret_paypal', 'CHANGE_ME_PRODUCTION_SECRET_PAYPAL'),
+(40, 'production_clientid_paypal', 'CHANGE_ME_PRODUCTION_CLIENTID_PAYPAL'),
 (41, 'production_tokenurl_paypal', 'https://api-m.paypal.com/v1/oauth2/token'),
 (42, 'comment_reviewer', 'administrator, principal'),
 (43, 'paypal_mode', 'sandbox'),
