# External Integrations **Analysis Date:** 2026-05-20 ## External Services ### Firebase Cloud Messaging (FCM) - **Purpose:** Push notifications to mobile/web clients when sensor thresholds are triggered - **SDK/Client:** `google/auth` ^1.49 (Google Auth for OAuth2 token generation) - **Implementation:** `src/app/Services/FcmService.php` - Authenticates via Service Account Credentials (`FIREBASE_CREDENTIALS` env → JSON file) - Sends topic-based notifications to `FCM_TOPIC_RAINFALL_WARNING` - Calls FCM HTTP v1 API: `https://fcm.googleapis.com/v1/projects/{projectId}/messages:send` - **Triggered by:** `src/app/Http/Controllers/Api/AlertController.php` (API endpoint `POST /api/alert`) - **Auth env vars:** `FIREBASE_PROJECT_ID`, `FIREBASE_CREDENTIALS`, `FCM_TOPIC_RAINFALL_WARNING` ### FTP Server (myvscada.com) - **Purpose:** Retrieving raw sensor data files (CSV) from remote SCADA FTP server - **Implementation:** `autoscript/sidesdecode.py` - FTP server: `myvscada.com`, credentials hardcoded in script - Folder structure: `files/SIDES/SUCCESS/{year}/{month}/{day}/` - Error folder: `files/SIDES/ERROR/` - Processes CSV files containing rainfall, water level, siren, and battery data ### SIDES API (Internal Callback) - **Purpose:** Alert notification trigger from ETL script to Laravel API - **Implementation:** `autoscript/sidesdecode.py` → `send_alert_to_laravel()` - Posts to `https://sides.tck.com.my/api/alert` - Payload: `{ stationid, level, stationtype }` - Received by: `src/app/Http/Controllers/Api/AlertController.php` ## Third-Party Libraries ### Google Auth (`google/auth` ^1.49) - **Connects to:** Google OAuth2 for Firebase service account authentication - **Used in:** `src/app/Services/FcmService.php` - **Purpose:** Generates access tokens for FCM HTTP v1 API calls ### Laravel DomPDF (`barryvdh/laravel-dompdf` ^3.1) - **Connects to:** N/A (local PDF generation) - **Used in:** Siren and notification history PDF exports - **Purpose:** Generates downloadable PDF reports from Blade templates ### Maatwebsite Excel (`maatwebsite/excel` ^3.1) - **Connects to:** N/A (local Excel generation) - **Used in:** `src/app/Exports/HourlyRainfallExport.php`, `src/app/Exports/WaterLevelExport.php` - **Purpose:** Export historical rainfall and water level data to Excel (.xlsx) ### psycopg2 (Python) - **Connects to:** PostgreSQL database directly (bypasses Laravel) - **Used in:** `autoscript/sidesdecode.py` - **Purpose:** Direct database insertion of sensor data from decoded CSV files ## Internal Services ### API Routes (REST) - **Base path:** `/api/` - **Defined in:** `src/routes/api.php` - **Endpoints:** - `GET /api/station/current` — Current station data (rainfall, water level, siren) - `GET /api/station/rainfall` — Rainfall-specific data - `GET /api/station/waterlevel` — Water level-specific data - `GET /api/station/notification` — Current day notifications - `GET /api/station/history` — 3-day notification history - `GET /api/station/siren` — Latest siren status - `GET /api/station/siren/history` — 3-day siren history - `POST /api/login` — Mobile/API authentication - `POST /api/alert` — Trigger FCM push notification ### Python ETL Script - **Location:** `autoscript/sidesdecode.py` - **Flow:** FTP download → CSV decode → PostgreSQL insert → API alert trigger - **Data types:** Rainfall, water level, siren status, battery levels - **Threshold logic:** Rainfall hourly ≥30mm (Warning), ≥60mm (Danger); Water level alert/warning/danger from CSV config - **Logs:** `autoscript/sidesdecode.log`, `autoscript/sidesdecode_error.log` ## Authentication Providers ### Web Authentication (Session-based) - **Provider:** Laravel Breeze (`laravel/breeze ^2.3`) - **Guard:** Session-based (`web` guard, `session` driver) - **User model:** `App\Models\User` (`src/app/Models/User.php`) - **Features:** Login, registration, email verification, password reset, password confirmation - **Role system:** `access_level` field on users table (1 = admin, 0 = regular) - **Account security:** `is_blocked` and `login_attempts` fields on users table - **Implementation:** `src/routes/auth.php`, `src/app/Http/Controllers/Auth/` ### API Authentication - **Provider:** Custom token-based (via `POST /api/login`) - **Implementation:** `src/app/Http/Controllers/Api/AuthController.php` - **Used by:** Mobile client or external data consumers ### Password Reset - **Custom notification:** `src/app/Notifications/ResetPasswordNotification.php` - **Channel:** Email (SMTP) - **Branded:** "SIDES - Password Reset" subject line ## Payment / Billing Not applicable — This is an environmental monitoring dashboard, no payment integration. ## Email / Notifications ### Email - **Default mailer:** `log` (writes to Laravel log, not actually sent in current config) — `src/config/mail.php` - **Configured transports:** SMTP, SES, Postmark, Resend, Sendmail, Log, Array - **Env vars:** `MAIL_MAILER`, `MAIL_HOST`, `MAIL_PORT`, `MAIL_USERNAME`, `MAIL_PASSWORD` - **From address:** Configurable via `MAIL_FROM_ADDRESS` and `MAIL_FROM_NAME` ### Push Notifications - **Firebase Cloud Messaging (FCM)** — Topic-based push notifications - **Implementation:** `src/app/Services/FcmService.php` - **Trigger:** Sensor threshold breaches detected by `autoscript/sidesdecode.py` ### In-App Notifications - **Notification views:** `src/resources/views/` — rainfall, water level, siren notification pages - **Data source:** `notification` table in PostgreSQL ## File Storage ### Primary Storage - **Default disk:** `local` — `src/storage/app/private/` (`src/config/filesystems.php`) - **Public disk:** `src/storage/app/public/` — symlinked to `public/storage` - **No cloud storage configured** — S3 config present but not active ### FTP File Management - **FTP server:** `myvscada.com` — remote sensor data storage - **File lifecycle:** SUCCESS folder → processed → optional move to SUCCESS/ERROR subfolders ## Queue / Background Jobs ### Queue Configuration - **Default driver:** `database` (`src/config/queue.php`) - **Table:** `jobs` (database-backed queue) - **Failed jobs:** `failed_jobs` table, driver `database-uuids` - **Job batching:** `job_batches` table - **Run command:** `php artisan queue:listen --tries=1` (via `composer dev`) - **Available drivers:** sync, database, beanstalkd, SQS, redis (not actively used beyond database) ## Caching ### Cache Configuration - **Default store:** `database` (`src/config/cache.php`) - **Table:** `cache` (database-backed cache) - **Available stores:** array, database, file, memcached, redis, dynamodb, octane, failover - **Redis:** Configured but not actively used (`src/config/database.php` has Redis connection block) - **Session driver:** `database` (sessions table) ## Search No dedicated search engine integration (Elasticsearch, Algolia, etc.). All queries use direct PostgreSQL with raw SQL joins and subqueries. --- *Integration audit: 2026-05-20*