# Codebase Structure **Analysis Date:** 2026-05-28 ## Directory Layout ``` src/ # Laravel application root ├── app/ # Application code │ ├── Exports/ # Excel export classes (Maatwebsite) │ ├── Http/ # HTTP layer │ │ ├── Controllers/ # Web controllers │ │ │ ├── Api/ # API controllers (JSON) │ │ │ └── Auth/ # Auth controllers (Laravel Breeze) │ │ ├── Middleware/ # Custom middleware │ │ └── Requests/ # Form request validation classes │ │ └── Auth/ # Auth-specific form requests │ ├── Models/ # Eloquent models │ ├── Notifications/ # Notification classes │ ├── Providers/ # Service providers │ ├── Services/ # Service classes │ └── View/ # Blade component classes │ └── Components/ # View components ├── bootstrap/ # Framework bootstrap │ ├── app.php # App config (middleware, routing registration) │ └── providers.php # Registered service providers ├── config/ # Configuration files ├── database/ # Database layer │ ├── factories/ # Model factories │ ├── migrations/ # Schema migrations (12 files) │ └── seeders/ # Database seeders ├── lang/ # Localization files │ ├── bm/ # Bahasa Malaysia │ └── en/ # English ├── public/ # Public web root │ ├── build/ # Vite build output │ ├── css/ # Compiled CSS │ ├── icon/ # Map icons │ ├── img/ # Images │ ├── js/ # Custom JS │ └── logo/ # Logo files ├── resources/ # Frontend resources │ ├── css/ # Source CSS (Tailwind + custom) │ ├── js/ # Source JS │ └── views/ # Blade templates │ ├── auth/ # Auth screens (6 files) │ ├── components/ # Shared Blade components (13 files) │ ├── layout/ # Main app views │ │ ├── admin/ # Admin panel views │ │ ├── graph/ # Chart views │ │ ├── notification/ # Notification views │ │ │ └── history/ # Notification history views │ │ └── siren/ # Siren views │ ├── layouts/ # Base layout templates (Breeze) │ ├── nav/ # Navigation partials (header, navbar, footer) │ ├── pdf/ # PDF export templates │ └── profile/ # Profile views │ └── partials/ ├── routes/ # Route definitions ├── storage/ # Framework storage ├── tests/ # Automated tests │ ├── Feature/ # Feature tests │ │ └── Auth/ # Auth feature tests │ ├── Unit/ # Unit tests │ └── storage/ # Test storage ├── vendor/ # Composer dependencies (excluded) ├── composer.json # PHP dependencies ├── package.json # Node dependencies (Vite, Tailwind) ├── vite.config.js # Vite configuration ├── tailwind.config.js # Tailwind CSS config └── phpunit.xml # PHPUnit config ``` ## Directory Purposes **`app/Http/Controllers/` — Web Controllers:** - Purpose: Handle authenticated web requests, query data, render Blade views - Contains: 11 controllers + 9 auth controllers + 3 API controllers - Key files: - `MapController.php`: Dashboard page — joins station + latest rainfall/waterlevel/siren data - `RainfallController.php`: Rainfall data display, 6-hour threshold, historical data, graph data, Excel export - `WaterLevelController.php`: Water level display, graph data, historical data, Excel export - `SirenController.php`: Siren status display, siren history, PDF export - `NotificationController.php`: Rainfall/waterlevel/siren notifications, history, PDF exports - `AdminController.php`: Station CRUD, user CRUD (access_level=1 only) - `cctvController.php`: CCTV link display for stations - `LocaleController.php`: Language switching (en/bm) - `ProfileController.php`: User profile edit/update/delete - `Controller.php`: Empty abstract base class **`app/Http/Controllers/Api/` — API Controllers:** - Purpose: JSON endpoints for external IoT devices and mobile clients - Contains: 3 controllers (no middleware/auth required on most endpoints) - Key files: - `StationController.php`: 7 endpoints — current data, rainfall, waterlevel, notifications, history, siren, siren history - `AuthController.php`: Custom username/password login returning JSON - `AlertController.php`: Relay station alerts via FCM push **`app/Http/Controllers/Auth/` — Auth Controllers (Laravel Breeze):** - Purpose: Handle authentication flow (login, register, password reset, email verification) - Contains: 9 controllers scaffolded by Laravel Breeze - Key files: - `AuthenticatedSessionController.php`: Login with custom blocked-user + login-attempt tracking - `RegisteredUserController.php`: User registration - `NewPasswordController.php`, `PasswordController.php`, `PasswordResetLinkController.php`: Password management - `VerifyEmailController.php`, `EmailVerificationNotificationController.php`, `EmailVerificationPromptController.php`: Email verification - `ConfirmablePasswordController.php`: Password confirmation **`app/Http/Middleware/` — Custom Middleware:** - Purpose: Request filtering and modification - Contains: 2 middleware classes - Key files: - `AdminMiddleware.php`: Checks `Auth::check()` + `Auth::user()->access_level === 1`, redirects to `/dashboard` on failure. Registered as alias `'admin'` in `bootstrap/app.php`. - `LocalizationMiddleware.php`: Reads `locale` from session, sets `App::setLocale()`. Appended to `web` middleware group in `bootstrap/app.php`. **`app/Http/Requests/` — Form Request Validation:** - Purpose: Encapsulate form validation and authorization logic - Contains: 2 form request classes - Key files: - `ProfileUpdateRequest.php`: Validates name + email (unique check ignoring current user) - `Auth/LoginRequest.php`: Rate-limited login validation (5 attempts), custom `username()` returning `'name'` **`app/Models/` — Eloquent Models:** - Purpose: Single model for Laravel authentication - Contains: `User.php` — only Eloquent model in the app - Key details: - Extends `Authenticatable`, uses `HasFactory`, `Notifiable` - Fillable: `name`, `email`, `password`, `access_level`, `login_attempts`, `is_blocked` - Hidden: `password`, `remember_token` - Casts: `email_verified_at` (datetime), `password` (hashed), `is_blocked` (boolean) - Overrides `sendPasswordResetNotification()` to use custom `ResetPasswordNotification` **`app/Services/` — Service Layer:** - Purpose: External API integrations - Contains: 1 service class - Key file: - `FcmService.php`: Firebase Cloud Messaging integration. Constructor reads `FIREBASE_PROJECT_ID` and `FIREBASE_CREDENTIALS` (path to JSON) from env. `sendToTopic()` authenticates via `google/auth` `ServiceAccountCredentials`, sends POST to FCM v1 HTTP API. **`app/Exports/` — Excel Exports:** - Purpose: Generate downloadable Excel spreadsheets - Contains: 2 export classes using `Maatwebsite\Excel` - Key files: - `HourlyRainfallExport.php`: Exports hourly rainfall with 24-column pivot (hour_00..hour_23) for a date range. Implements `FromCollection`, `WithHeadings`, `ShouldAutoSize`. - `WaterLevelExport.php`: Exports water level readings with alert/warning/danger thresholds for a station+date. Implements `FromCollection`, `WithHeadings`, `ShouldAutoSize`. **`app/Notifications/` — Notification Classes:** - Purpose: Email notifications sent by Laravel - Contains: 1 notification class - Key file: - `ResetPasswordNotification.php`: Queueable email notification for password reset. Sends via `mail` channel with SIDES branding. **`app/Providers/` — Service Providers:** - Purpose: Framework bootstrapping - Contains: 1 service provider - Key file: - `AppServiceProvider.php`: Currently empty `register()` and `boot()` methods (no custom services registered). **`app/View/Components/` — Blade Components:** - Purpose: Render Blade component views - Contains: 2 component classes - Key files: - `AppLayout.php`: Renders `layouts.app` (Breeze default authenticated layout) - `GuestLayout.php`: Renders `layouts.guest` (Breeze default guest layout) **`routes/` — Route Definitions:** - Purpose: Map HTTP requests to controllers - Contains: 4 route files - Key files: - `web.php` (85 lines): All web routes — auth-protected (dashboard, rainfall, waterlevel, siren, notification, CCTV), admin-protected (station management, user management), and public (dashboard, stations, locale switch). Includes `auth.php` at the end. - `auth.php` (59 lines): Auth routes scaffolded by Breeze — guest routes (login, register, password reset), auth routes (verify email, confirm password, logout). - `api.php` (19 lines): Public API routes — station data endpoints (7 GET), login, alert push. No middleware required on most endpoints. - `console.php` (8 lines): Single `inspire` Artisan command (default Laravel). **`database/migrations/` — Schema Migrations:** - Purpose: Define and evolve database schema - Contains: 12 migration files ordered by timestamp - Key files: - `0001_01_01_000000_create_users_table.php`: Users, password_reset_tokens, sessions tables (Laravel default) - `2025_11_06_071853_create_station_table.php`: `station` table — stationid (PK), name, district, lng, lat, mainriverbasin, subriverbasin, rainfall, waterlevel - `2025_11_06_072709_create_rainfall__table.php`: `rainfall` table — stationid, timestamp, anncum, daily, hourly, currentrf, battery - `2025_11_06_072738_create_waterlevel_table.php`: `waterlevel` table — stationid, datetime, waterlevel, alert, warning, danger - `2025_11_07_024940_create_notification_table.php`: `notification` table — stationid, timestamp, stationtype, level, active_time - `2025_11_07_031601_create_siren__table.php`: `siren` table — stationid, stationtype, active_time, level - `2025_11_07_063825_add_access_level_to_users_table.php`: Adds `access_level` (int, default 2) to users - `2025_11_07_065418_add_block_fields_to_users_table.php`: Adds `is_blocked` (boolean) and `login_attempts` (int) to users - `2025_11_08_004548_add_siren_to_station_table.php`: Adds `siren` (int, nullable) to station - `2025_11_25_113158_add_cctvlink_to_station.php`: Adds `cctv_link` (string, nullable) to station **`resources/views/` — Blade Templates:** - Purpose: Render all HTML and PDF output - Contains: ~40+ Blade template files organized by domain - Structure: - `layout/app.blade.php` — Main authenticated layout (`@include nav.header+navbar`, `@yield content1/content2/content3`) - `layout/homeapp.blade.php` — Public layout (no auth, full-width) - `layout/dashboard.blade.php` — Home page with Leaflet map + station data table - `layout/rainfall.blade.php` — Rainfall data table with 7-day daily columns + graph modal - `layout/waterlevel.blade.php` — Water level data table - `layout/threshold.blade.php` — 6-hour early warning threshold view - `layout/historicalrainfall.blade.php` — Historical rainfall with date range picker - `layout/historicalwl.blade.php` — Historical water level - `layout/cctv.blade.php` — CCTV links for stations - `layout/home.blade.php` — Public landing page (extends `layout.homeapp`) - `layout/siren/home.blade.php`, `layout/siren/history.blade.php` — Siren status and history - `layout/notification/rainfall.blade.php`, `layout/notification/waterlevel.blade.php`, `layout/notification/siren.blade.php` — Current notifications - `layout/notification/history/rainfall.blade.php`, `layout/notification/history/waterlevel.blade.php` — Notification history - `layout/graph/rainfall.blade.php` — Rainfall graph page - `layout/admin/stationmgmt.blade.php` (352 lines) — Station management CRUD interface - `layout/admin/usermgmt.blade.php` — User management CRUD interface - `pdf/rfhistory.blade.php`, `pdf/wlhistory.blade.php`, `pdf/sirenhistory.blade.php` — PDF export templates - `nav/header.blade.php` — HTML head, CSS, Leaflet, Flatpickr, jQuery CDNs - `nav/navbar.blade.php` — Full responsive navigation (desktop + mobile sidebar) - `nav/footer.blade.php` — Footer partial - `auth/*.blade.php` — Login, register, forgot/reset password, verify-email, confirm-password screens - `components/*.blade.php` — 13 shared Blade components (application-logo, dropdown, input-label, modal, nav-link, buttons, etc.) - `layouts/app.blade.php`, `layouts/guest.blade.php` — Breeze default layouts (component-based) - `profile/edit.blade.php` — Profile edit page **`lang/` — Localization Files:** - Purpose: Internationalization strings for two locales - Contains: `en/` (English) and `bm/` (Bahasa Malaysia) directories - Key files: `messages.php` (UI text), `toast.php` (flash messages), `auth.php`, `validation.php`, `passwords.php`, `pagination.php` **`public/` — Public Web Root:** - Purpose: Entry point for HTTP requests (`index.php`), static assets - Contains: Compiles CSS (`css/style.css`), JavaScript (`js/script.js`, `js/graph.js`), Leaflet map icons (`icon/`), images (`img/`), logos (`logo/`), Vite build output (`build/`) **`tests/` — Automated Tests:** - Purpose: PHPUnit test suite - Contains: Feature tests and unit tests - Key files: - `tests/Feature/Auth/`: 6 auth test files (most appear empty — e.g., `AuthenticationTest.php` has 0 lines) - `tests/Feature/ExampleTest.php`, `tests/Feature/ProfileTest.php` - `tests/Unit/ExampleTest.php` ## Key File Locations **Entry Points:** - `public/index.php`: HTTP entry point (Laravel front controller) - `artisan`: CLI entry point - `bootstrap/app.php`: Application configuration (middleware aliases, routing, exceptions) - `bootstrap/providers.php`: Registered service providers **Configuration:** - `config/app.php`: App name, env, URL, timezone, locale, providers, aliases - `config/database.php`: DB connection (default: sqlite, but code uses PostgreSQL) - `config/auth.php`: Auth guard (`web`, session), user provider, password reset config - `config/mail.php`: Mail driver config (default: log) - `config/filesystems.php`: Disk configs (local, public, s3) - `config/services.php`: Third-party API keys (postmark, resend, ses, slack) - `config/queue.php`: Queue driver (default: database) - `config/session.php`: Session driver config - `config/cache.php`: Cache driver config - `.env`: Environment variables (exists but not read — contains credentials) **Core Routing:** - `routes/web.php`: All web routes (85 lines) - `routes/auth.php`: Auth routes (59 lines, included from web.php) - `routes/api.php`: API routes (19 lines) - `routes/console.php`: Console commands (8 lines) **Database Schema:** - `database/migrations/`: 12 migration files defining 8+ tables - `database/seeders/DatabaseSeeder.php`: Seeds admin user **Static Assets:** - `resources/css/app.css`: Tailwind CSS source - `resources/css/style.css`: Custom CSS - `resources/js/app.js`: Alpine.js + Bootstrap app JS - `resources/js/bootstrap.js`: Axios + Echo bootstrap - `resources/js/script.js`: Custom app scripts - `resources/js/graph.js`: Chart.js graph rendering ## Naming Conventions **Files:** - **Controllers**: PascalCase suffixed with `Controller` (e.g., `RainfallController.php`, `AdminController.php`) - **Models**: PascalCase singular (only `User.php`) - **Middleware**: PascalCase suffixed with `Middleware` (e.g., `AdminMiddleware.php`) - **Requests**: PascalCase suffixed with `Request` (e.g., `ProfileUpdateRequest.php`) - **Exports**: PascalCase suffixed with `Export` (e.g., `HourlyRainfallExport.php`) - **Services**: PascalCase suffixed with `Service` (e.g., `FcmService.php`) - **Notifications**: PascalCase suffixed with `Notification` (e.g., `ResetPasswordNotification.php`) - **Migrations**: `YYYY_MM_DD_HHMMSS_create_{table}_table.php` or `..._add_{column}_to_{table}_table.php` - **Blade views**: Lowercase kebab-case (e.g., `historicalrainfall.blade.php`, `stationmgmt.blade.php`) - **Routes file**: Lowercase (`web.php`, `api.php`, `auth.php`, `console.php`) - **Config files**: Lowercase (`app.php`, `database.php`) **Directories:** - Namespace-matching PascalCase under `app/` (e.g., `Http/Controllers/Api/`) - Lowercase under `resources/views/` (e.g., `layout/admin/`, `layout/notification/history/`) - Lowercase under `config/`, `database/`, `routes/`, `lang/` ## Where to Add New Code **New Feature (e.g., new data type):** - Controller: `app/Http/Controllers/{Name}Controller.php` — extends `Controller`, uses `DB` facade - Routes: `routes/web.php` — add under appropriate middleware group (`auth` or `admin`) - Views: `resources/views/layout/{name}/` — create view directory with `home.blade.php`, `history.blade.php` etc. - API endpoint: `routes/api.php` + `app/Http/Controllers/Api/{Name}Controller.php` - Exports: `app/Exports/{Name}Export.php` + `resources/views/pdf/{name}history.blade.php` if needed **New API Endpoint:** - Add route to `routes/api.php` - Add method to existing controller in `app/Http/Controllers/Api/` or create new controller **New Middleware:** - Create class in `app/Http/Middleware/` - Register alias or group in `bootstrap/app.php` → `withMiddleware()` **New Service:** - Create class in `app/Services/` - Inject via constructor or `app()` helper in controllers **New Database Table:** - Create migration in `database/migrations/` using `YYYY_MM_DD_HHMMSS_create_{table}_table.php` format - Add seeder entry to `database/seeders/DatabaseSeeder.php` **New Translation:** - Add key to both `lang/en/messages.php` and `lang/bm/messages.php` (or corresponding domain file) - Use `@lang('messages.key')` in Blade or `__('messages.key')` in PHP **New Validation:** - Add inline `$request->validate([...])` for simple cases - Create `app/Http/Requests/{Name}Request.php` for reusable validation ## Special Directories **`resources/views/layout/`:** - Purpose: Main application views (the primary view directory used by all web controllers) - Contains: 14 files + 4 subdirectories (admin/, graph/, notification/, siren/) - The `layout.app` Blade layout is the base template accessed via `@extends('layout.app')` — this includes nav, header, footer, modals, scripts, CSS **`resources/views/layouts/`:** - Purpose: Laravel Breeze default layout templates (used by auth screens and view components) - Contains: `app.blade.php` (component-based slot layout), `guest.blade.php`, `navigation.blade.php` - This is a SEPARATE layout system from `resources/views/layout/` — the application uses `layout.app` for authenticated pages and `layouts.app` only for auth scaffolding views **`public/js/` and `public/css/`:** - Purpose: Compiled/minified static assets (not source) - Contains: `script.js`, `graph.js` — JavaScript files directly placed in public (NOT compiled through Vite). These are loaded via `