Imported from HazemDesign/Baladi-App (
Backend/BALADI-GRADUATION-PROJECT/AGENTS.md). Install upstream withnpx skills add HazemDesign/Baladi-App --skill BALADI-GRADUATION-PROJECT. Copyright stays with the author.
BALADI-GRADUATION-PROJECT - AGENTS.md
Project Overview
- Framework: Laravel 12 (PHP 8.3.16)
- Database: SQLite (local), MySQL (production)
- Admin Panel: Blade templates with Tailwind CSS (CDN)
- API: RESTful endpoints for Flutter mobile app
Critical Commands
- Start server:
php artisan serve --host=127.0.0.1 --port=8000 - Run migrations:
php artisan migrate - Seed database:
php artisan db:seed - Clear cache:
php artisan cache:clear && php artisan config:clear && php artisan route:clear && php artisan view:clear
File Structure
- Routes:
routes/web.php(redirects to login),routes/admin.php(all admin routes) - Admin Controllers:
app/Http/Controllers/Admin/ - API Controllers:
app/Http/Controllers/Api/ - Views:
resources/views/admin/ - Layout:
resources/views/admin/layouts/app.blade.php - Translations:
lang/ar.json,lang/en.json(JSON format, used with__('key'))
Key Conventions
- Language: Session-based via
SetAdminLocalemiddleware, default Arabic - RTL/LTR: Auto-switched based on language — Arabic = RTL (right sidebar), English = LTR (left sidebar)
- Dark theme:
bg-gray-900base, Tailwind dark colors throughout - Font: Cairo (Google Fonts)
- City-scoped access: Admins can only access reports from assigned governorates via
FiltersByAdminGovernoratestrait - Severity values:
Low,Medium,High,Critical(NOTpending) - Status values:
pending,in_progress,resolved,rejected
SQLite Compatibility
When writing raw SQL queries, always check the driver:
$driver = DB::connection()->getDriverName();
if ($driver === 'sqlite') {
// Use strftime(), julianday()
} else {
// Use YEAR(), MONTH(), TIMESTAMPDIFF()
}
Admin Routes (from routes/admin.php)
- Auth:
/admin/login,/admin/logout - Dashboard:
/admin/dashboard,/admin/dashboard/ai-insights,/admin/dashboard/export-reports - Resources:
reports,categories,users,notifications,comments - Settings:
/admin/settings(GET),/admin/settings(POST) - Super Admin only:
governorates,admins - Export routes always defined BEFORE resource routes (e.g.,
reports/exportbeforereports/{report})
Sidebar Behavior
- Desktop expanded: 16rem width, icons + labels visible
- Desktop mini: 4rem width, icons centered, labels hidden
- Mobile: Full overlay sidebar, tap overlay to close
- Toggle button: Always in header bar — switches between full ↔ mini on desktop
- State saved:
localStoragekeyadminSidebarMode(values:full,mini,closed) - Settings page:
/admin/settings— choose sidebar state (full/mini) + language (Arabic/English) - Sidebar position: Auto-flips with language — Arabic = right, English = left
Session Keys
admin_language—'ar'or'en'admin_sidebar_state—'full'or'mini'
Middleware
admin_locale— SetsApp::setLocale()from sessionadmin_languageadmin— Checks user has admin rolesuper_admin— Checks user has admin role (full access)
Known Gotchas
- Never put
pendingin severity validation rules — it's a status, not severity - Export routes must be registered before resource routes to avoid route conflicts
ReportController@storehas extensive AI image analysis fallback logic — do not simplifyCache::remember()closures must capture$driverviause ($driver)when containing SQLite-specific queries- Use
__('key')for translations — keys are inlang/{ar,en}.json - The
admin_localemiddleware is applied to the entire admin route prefix group