# Coding Conventions **Analysis Date:** 2026-05-20 ## Naming Conventions **Files:** - Controllers: PascalCase (e.g., `SirenController.php`, `AdminController.php`, `MapController.php`) - **Exception:** `cctvController.php` uses lowercase — inconsistent with project convention - Models: PascalCase singular (e.g., `User.php`) - Exports: PascalCase (e.g., `WaterLevelExport.php`, `HourlyRainfallExport.php`) - Notifications: PascalCase (e.g., `ResetPasswordNotification.php`) - Services: PascalCase (e.g., `FcmService.php`) - Middleware: PascalCase (e.g., `AdminMiddleware.php`, `LocalizationMiddleware.php`) - Form Requests: PascalCase (e.g., `ProfileUpdateRequest.php`, `LoginRequest.php`) - Migrations: `YYYY_MM_DD_HHMMSS_description_snake_case.php` - Blade views: `snake_case` directories + `kebab-case` or `snake_case` files (e.g., `layout/notification/rainfall.blade.php`) - JavaScript: `camelCase.js` (e.g., `homemap.js`, `graph.js`, `rfhistory.js`) **Classes:** - PascalCase for all classes, following PSR-4 autoloading - Controllers suffixed with `Controller` (e.g., `RainfallController`) - Exports suffixed with `Export` (e.g., `HourlyRainfallExport`) **Methods:** - camelCase (e.g., `stationDisplay()`, `rainfallSum()`, `exportHistoricalWl()`) - **Exception:** `SirenHistory()` uses PascalCase — inconsistent - Public methods in controllers follow action naming: `index()`, `store()`, `update()`, `destroy()`, `edit()` **Variables:** - camelCase for local variables (e.g., `$stationFilter`, `$rainfallData`, `$displayDate`) - camelCase for class properties (e.g., `$stationid`, `$startDate` in Export classes) - `$stationid` used as one word (not `$stationId`) — project-specific convention **Database Tables:** - snake_case lowercase singular (e.g., `station`, `rainfall`, `waterlevel`, `siren`, `notification`, `users`) - `users` is the only plural table name **Columns:** - snake_case lowercase (e.g., `stationid`, `active_time`, `access_level`, `login_attempts`, `is_blocked`, `cctv_link`) - No consistent convention: some use compound words without underscore (e.g., `stationid`, `waterlevel`) ## Code Style **Formatting:** - `.editorconfig` present at both project root and `src/` - Indent: 4 spaces (no tabs, except Makefiles) - Charset: UTF-8 - End of line: LF - Trailing whitespace trimmed (except `.md` files) - YAML files: 2-space indent - No ESLint or Prettier configured for JavaScript **Linting:** - `laravel/pint` installed as dev dependency (PHP code style fixer) - No evidence of a `pint.json` configuration file — using defaults - No frontend linting tools configured **Bracket Style:** - Opening braces on same line for classes and methods - Control structures: opening brace on same line (K&R style) - Multi-line function calls and arrays: trailing comma not consistently used **Import/Use Statement Organization:** - Laravel framework imports first - Then third-party packages (e.g., `Carbon`, `Maatwebsite\Excel`, `DomPDF`) - Then application imports (e.g., `App\Models\User`, `App\Services\FcmService`) - Blank line between groups is not consistently applied - Example from `WaterLevelController.php`: ```php use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Carbon\Carbon; // Add this for Export data to excel use App\Exports\WaterLevelExport; use Maatwebsite\Excel\Facades\Excel; ``` **Docblock Usage:** - PHPDoc blocks present on model properties (`$fillable`, `$hidden`, `casts()`) - Docblocks on factory methods and notification methods (Breeze scaffolded) - Custom controllers use inline `//` comments extensively rather than docblocks - Comment style in controllers follows a pattern: ```php // Function Retrieve Current Water Level Data public function index(Request $request) ``` - Each SQL query is annotated with block comments: ```php // TABLE : STATION JOIN TABLE WATERLEVEL // COLUMN : name,datetime,waterlevel // INPUT : $stationCondition from resources/views/... // OUTPUT : resources/views/layout/waterlevel.blade.php ``` ## File Organization **How files are grouped:** - Controllers grouped by domain in flat structure under `app/Http/Controllers/` - API controllers in `app/Http/Controllers/Api/` subdirectory - Auth controllers in `app/Http/Controllers/Auth/` subdirectory (Breeze scaffolded) - Exports in `app/Exports/` - Services in `app/Services/` - Notifications in `app/Notifications/` - Views follow a `layout.{domain}` naming pattern (e.g., `layout.rainfall`, `layout.admin.stationmgmt`) **One class per file:** - Adhered to throughout — one class per file **Directory naming:** - All lowercase directories (e.g., `Controllers/`, `Models/`, `Services/`, `Exports/`) - Views use nested lowercase directories (e.g., `layout/notification/history/`) ## Git Conventions **Branch naming:** - Only 2 commits in the repository — no discernible branch naming convention **Commit message patterns:** - Observed messages: - `first commit` - `fix: configuration docker-compose.yml` - The second commit suggests a possible `type: description` convention (fix:, feat:, etc.) ## Laravel-Specific Patterns **Eloquent Model Patterns:** - Only `User.php` exists as an Eloquent model (`app/Models/User.php`) - `HasFactory` and `Notifiable` traits used on User - `$fillable` array for mass assignment (not `$guarded`) - `casts()` method (Laravel 12 style) instead of `$casts` property - Custom notification override: `sendPasswordResetNotification()` **Controller Patterns:** - **Not resource controllers** — methods are custom-named (e.g., `stationDisplay()`, `userDisplay()`, `storeStation()`) - Heavy use of raw SQL via `DB::select()` and `DB::table()` instead of Eloquent ORM - `collect(DB::select(...))` pattern to wrap raw SQL results into collections - Controller validation done inline with `$request->validate()` — not consistently using Form Requests - Redirect pattern: `redirect()->back()->with('success', __('toast.key'))` - View compact pattern: `return view('blade.path', compact('var1', 'var2'))` **Form Request Usage:** - `ProfileUpdateRequest` for profile updates (`app/Http/Requests/ProfileUpdateRequest.php`) - `LoginRequest` for authentication (`app/Http/Requests/Auth/LoginRequest.php`) - Admin controller does inline `$request->validate()` instead of Form Requests - **Inconsistent:** Form Requests exist but most validation is inline **Resource/API Resource Usage:** - Not used — API responses use `response()->json($data)` directly - No API Resource classes defined **Policy Usage:** - Not used — authorization handled via custom `AdminMiddleware` checking `access_level` - `app/Http/Middleware/AdminMiddleware.php` checks `Auth::user()->access_level !== 1` **Event/Listener Patterns:** - Not used — no events or listeners defined - Notification push (FCM) is called directly from API controller **Route Patterns:** - Named routes used consistently: `->name('rainfall')`, `->name('stationmanagement.store')` - Route grouping by middleware: `Route::middleware('auth')`, `Route::middleware(['admin'])` - Admin routes use POST for updates (not PUT/PATCH) — non-RESTful - API routes in `routes/api.php` with no auth middleware **Localization:** - Bilingual: English (`en`) and Bahasa Malaysia (`bm`) in `resources/lang/` - `LocalizationMiddleware` sets locale via session - `__('key')` helper used for translations in views and controllers **Middleware:** - Custom middleware registered in `bootstrap/app.php` - `AdminMiddleware` for admin-only routes - `LocalizationMiddleware` for language switching **Export Pattern (Maatwebsite Excel):** - Export classes implement `FromCollection`, `WithHeadings`, `ShouldAutoSize` - Constructor injection for filter parameters - Raw SQL queries in `collection()` method - `headings()` method returns array of column names **PDF Export Pattern (DomPDF):** - `Pdf::loadView('blade.path', compact('data'))->setPaper('a4','potrait')` - Note: `'potrait'` is a typo — should be `'portrait'` (present in multiple files) --- *Convention analysis: 2026-05-20*