Files
sides/.planning/codebase/INTEGRATIONS.md
2026-05-28 16:25:22 +08:00

194 lines
9.3 KiB
Markdown

# External Integrations
**Analysis Date:** 2026-05-28
## APIs & External Services
**Firebase Cloud Messaging (FCM):**
- Service: Firebase Cloud Messaging — push notification delivery to mobile devices via topic-based messaging
- Implementation: `src/app/Services/FcmService.php`
- Auth: Service Account JSON file (path configured via `FIREBASE_CREDENTIALS` env var); uses `Google\Auth\Credentials\ServiceAccountCredentials` to fetch OAuth2 access tokens
- Scopes: `https://www.googleapis.com/auth/firebase.messaging`
- Endpoint: `https://fcm.googleapis.com/v1/projects/{projectId}/messages:send`
- Env vars: `FIREBASE_PROJECT_ID`, `FIREBASE_CREDENTIALS`
- Topic mapping: `FCM_TOPIC_RAINFALL_WARNING` env var (set in `src/app/Http/Controllers/Api/AlertController.php`)
**Google Auth Library:**
- Package: `google/auth ^1.49` (`src/composer.json`)
- Purpose: Generates OAuth2 bearer tokens for Firebase API calls using service account credentials
- Implementation: `src/app/Services/FcmService.php` — creates `ServiceAccountCredentials` instance and calls `fetchAuthToken()`
**Amazon SES (Simple Email Service):**
- Configured in `src/config/services.php``ses` key with `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION`
- Mail transport: `ses` driver in `src/config/mail.php`
- Also used as a transport in `roundrobin` failover group
**Postmark:**
- Configured in `src/config/services.php``postmark` key with `POSTMARK_API_KEY` env var
- Mail transport: `postmark` driver in `src/config/mail.php`
- Optional `message_stream_id` config commented out
- Used in `roundrobin` failover group with SES
**Resend:**
- Configured in `src/config/services.php``resend` key with `RESEND_API_KEY` env var
- Mail transport: `resend` driver in `src/config/mail.php`
**Slack:**
- Notifications: configured in `src/config/services.php``slack.notifications` with `SLACK_BOT_USER_OAUTH_TOKEN` and `SLACK_BOT_USER_DEFAULT_CHANNEL` env vars
- Logging: Slack webhook channel available in `src/config/logging.php``LOG_SLACK_WEBHOOK_URL` env var for critical-level log alerts
**Papertrail:**
- Logging channel configured in `src/config/logging.php``SyslogUdpHandler` via `PAPERTRAIL_URL` and `PAPERTRAIL_PORT` env vars with TLS
## Data Storage
**Databases:**
- PostgreSQL 18.1
- Container: `sides-db` (image `postgres:18.1`)
- Connection: `pgsql` driver; env vars `DB_HOST`, `DB_PORT` (5432), `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD`
- Persistence: `./docker/postgres/data:/var/lib/postgres/data`
- Exposed port: 5432
- Schema: `public`
- Client library: `pdo_pgsql` and `pgsql` PHP extensions installed in Docker image
**Redis:**
- Configured in `src/config/database.php` under the `redis` key
- Client: `phpredis` (configured via `REDIS_CLIENT` env var)
- Separate connections for `default` (DB 0) and `cache` (DB 1)
- Retry/backoff: decorrelated jitter strategy, max 3 retries, 100ms base, 1000ms cap
- Used as optional driver for: cache (`CACHE_STORE=redis`), queue (`QUEUE_CONNECTION=redis`), session (`SESSION_DRIVER=redis`)
**File Storage:**
- Local disk (`local`): `storage/app/private/` — default filesystem
- Public disk (`public`): `storage/app/public/` — symlinked to `public/storage`
- S3 disk (`s3`) configured for AWS S3: env vars `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION`, `AWS_BUCKET`, `AWS_URL`, `AWS_ENDPOINT`
- Default disk: selected via `FILESYSTEM_DISK` env var (falls back to `local`)
## Authentication & Identity
**Auth Provider:**
- Laravel's built-in session-based authentication (`src/config/auth.php`)
- Guard: `web` driver using `session`
- Provider: `users` using `eloquent` driver on `App\Models\User`
- Password resets via `password_reset_tokens` table; 60-minute expiry; 60-second throttle
- Custom `access_level` field on `users` table (integer, default `2`), with `is_blocked` and `login_attempts` fields for account lockout
- API authentication: custom tokenless login in `src/app/Http/Controllers/Api/AuthController.php` — validates username/password via raw SQL and `Hash::check()`, returns user data with `access_level`
**Email Verification:**
- Built-in Laravel email verification flow (`MustVerifyEmail` trait available but not used in `App\Models\User`)
- Routes use `signed` middleware with throttling (`6:1`)
## Monitoring & Observability
**Error Tracking:**
- Not detected — no Sentry, Bugsnag, or similar APM integration
**Logs:**
- Laravel logging via Monolog (`src/config/logging.php`)
- Default channel: `stack``single` (writes to `storage/logs/laravel.log`)
- Available channels: `single`, `daily` (14-day retention), `slack`, `papertrail`, `stderr`, `syslog`, `errorlog`
- `pail` CLI log viewer available in dev (`laravel/pail ^1.2.2`)
**Dozzle:**
- Log viewer container (`amir20/dozzle:latest`) in `docker-compose.yml`
- Port: 777
- Container actions and shell access enabled
## CI/CD & Deployment
**Hosting:**
- Not explicitly declared — Docker-based deployment assumed
- Artisan serve on port 8000 (dev); Nginx on port 8080/8443 (production via Docker)
- `composer setup` script performs full bootstrap: `composer install`, `.env` creation, `key:generate`, migrations, npm install + build
**CI Pipeline:**
- Not detected — no GitHub Actions, GitLab CI, or similar config files found
## Environment Configuration
**Required env vars (from code analysis):**
| Variable | Used In | Purpose |
|---|---|---|
| `APP_KEY` | `config/app.php` | Laravel encryption key (AES-256-CBC) |
| `APP_ENV` | `config/app.php` | Environment (local/production) |
| `APP_DEBUG` | `config/app.php` | Debug mode toggle |
| `APP_URL` | `config/app.php`, `config/filesystems.php` | Application base URL |
| `APP_NAME` | `config/app.php`, `config/session.php`, `config/cache.php` | Application name |
| `DB_CONNECTION` | `config/database.php`, `config/queue.php` | Database connection (default: `sqlite`) |
| `DB_HOST`, `DB_PORT`, `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD` | `config/database.php` | PostgreSQL connection |
| `SESSION_DRIVER` | `config/session.php` | Session backend (default: `database`) |
| `SESSION_DRIVER` | `config/session.php` | Session backend (default: `database`) |
| `QUEUE_CONNECTION` | `config/queue.php` | Queue driver (default: `database`) |
| `CACHE_STORE` | `config/cache.php` | Cache backend (default: `database`) |
| `FILESYSTEM_DISK` | `config/filesystems.php` | Storage disk (default: `local`) |
| `MAIL_MAILER` | `config/mail.php` | Mail driver (default: `log`) |
| `FIREBASE_PROJECT_ID` | `FcmService.php` | Firebase project identifier |
| `FIREBASE_CREDENTIALS` | `FcmService.php` | Path to Firebase service account JSON |
| `FCM_TOPIC_RAINFALL_WARNING` | `AlertController.php` | FCM topic for alerts |
| `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD` | `docker-compose.yml` | PostgreSQL container credentials |
| `PGADMIN_EMAIL`, `PGADMIN_PASSWORD` | `docker-compose.yml` | pgAdmin login credentials |
**Secrets location:**
- Environment variables via `.env` file (not committed per `.env.example` pattern)
- Docker Compose `environment` blocks reference `${VAR}` from `.env` file (no hardcoded secrets)
## Frontend CDN Dependencies
**Loaded via CDN (not bundled by Vite):**
- Bootstrap 5.3.3 (CSS + JS bundle) — `cdn.jsdelivr.net`
- Leaflet 1.9.4 (CSS + JS) — `unpkg.com`
- Chart.js 4.4.0 + chartjs-plugin-zoom 2.1.1 — `cdn.jsdelivr.net`
- jsPDF 2.5.1 + jspdf-autotable 3.5.28 — `cdnjs.cloudflare.com`
- jQuery 3.6.0 — `cdn.jsdelivr.net`
- Boxicons 2.1.4 — `unpkg.com`
- Flatpickr — `cdn.jsdelivr.net`
## Webhooks & Callbacks
**Incoming:**
- Not detected — no webhook endpoint routes found
**Outgoing:**
- Firebase FCM HTTP POST to `fcm.googleapis.com` for push notifications (`FcmService.php`)
- Slack webhook for log alerts (configured via `LOG_SLACK_WEBHOOK_URL`)
## Queue & Job Processing
**Queue Driver:**
- Default: `database` (using PostgreSQL `jobs` table)
- Alternate drivers configured: `sync`, `beanstalkd`, `sqs`, `redis`, `deferred`, `background`, `failover`
- Failover chain: `database``deferred`
- Job batching table: `job_batches`
- Failed jobs table: `failed_jobs` (driver: `database-uuids`)
**Queue Worker:**
- Dev command: `php artisan queue:listen --tries=1` (part of `composer dev` script, runs via `concurrently`)
## Session Management
**Session Driver:**
- Default: `database` (using PostgreSQL `sessions` table)
- Alternate drivers available: `file`, `cookie`, `memcached`, `redis`, `dynamodb`, `array`
- Lifetime: 120 minutes (configurable via `SESSION_LIFETIME`)
- Cookie: `{app_name}-session`, HTTP-only, SameSite=Lax
## Localization
**Supported Locales:**
- English (`en`): `src/lang/en/``messages.php`, `toast.php`, `auth.php`, `validation.php`, `pagination.php`, `passwords.php`
- Bahasa Malaysia (`bm`): `src/lang/bm/` — same file set as English
- Locale switching: `src/app/Http/Controllers/LocaleController.php` via `GET /locale/{locale}` route
- Stored in session via `Session::put('locale', $lang)`
## Management & Utility Containers
**Docker auxiliary services (in `docker-compose.yml`):**
- **pgAdmin4** (`dpage/pgadmin4`) - Port 5050, for PostgreSQL management
- **Adminer** - Port 6060, lightweight DB management
- **Dozzle** (`amir20/dozzle:latest`) - Port 777, real-time Docker log viewer
- **Filebrowser** (`gtstef/filebrowser:stable`) - Port 8900, web file manager with access to `/root/sides`
---
*Integration audit: 2026-05-28*