# Configuration SIDES uses a layered configuration approach: a root `.env` for Docker Compose infrastructure, and a separate `src/.env` for the Laravel application. This document covers both. --- ## Environment Variables Overview ### Root `.env` (Docker Compose) Located at the project root. Controls container-level configuration for PostgreSQL, pgAdmin, Firebase, admin seeding, and FTP access. See `.env.example` for the full list. | Variable | Required | Default | Description | |---|---|---|---| | `POSTGRES_DB` | Yes | — | PostgreSQL database name | | `POSTGRES_USER` | Yes | — | PostgreSQL user | | `POSTGRES_PASSWORD` | Yes | — | PostgreSQL password | | `PGADMIN_EMAIL` | Yes | — | pgAdmin login email | | `PGADMIN_PASSWORD` | Yes | — | pgAdmin login password | | `FIREBASE_PROJECT_ID` | Yes | — | Firebase project identifier | | `FIREBASE_CREDENTIALS` | Yes | — | Path to Firebase credentials JSON file | | `FCM_TOPIC_RAINFALL_WARNING` | No | `rainfall_warning` | FCM topic for rainfall warnings | | `FCM_TOPIC_RAINFALL_DANGER` | No | `rainfall_danger` | FCM topic for rainfall danger alerts | | `FCM_TOPIC_WATERLEVEL_ALERT` | No | `waterlevel_alert` | FCM topic for water level alerts | | `FCM_TOPIC_WATERLEVEL_DANGER` | No | `waterlevel_danger` | FCM topic for water level danger alerts | | `ADMIN_EMAIL` | No | `admin@example.com` | Admin email used by `DatabaseSeeder` | | `ADMIN_PASSWORD` | No | `admin123` | Admin password used by `DatabaseSeeder` | | `FTP_SERVER` | No | — | FTP server hostname for `sidesdecode.py` | | `FTP_USERNAME` | No | — | FTP username | | `FTP_PASSWORD` | No | — | FTP password | ### App `.env` (Laravel) Located at `src/.env`. Controls Laravel framework and application settings. See `src/.env.example` for the full list. | Variable | Required | Default | Description | |---|---|---|---| | `APP_NAME` | Yes | `SIDES` | Application name | | `APP_ENV` | Yes | `local` | Environment: `local`, `production` | | `APP_KEY` | Yes | — | Encryption key (generated via `php artisan key:generate`) | | `APP_DEBUG` | Yes | `true` | Enable debug mode (`false` in production) | | `APP_URL` | Yes | `http://localhost` | Application URL | | `DB_CONNECTION` | Yes | `pgsql` | Database driver | | `DB_HOST` | Yes | `postgres` | Database host (Docker service name) | | `DB_PORT` | Yes | `5432` | Database port | | `DB_DATABASE` | Yes | `${POSTGRES_DB}` | Database name (references root `.env`) | | `DB_USERNAME` | Yes | `${POSTGRES_USER}` | Database user (references root `.env`) | | `DB_PASSWORD` | Yes | `${POSTGRES_PASSWORD}` | Database password (references root `.env`) | | `SESSION_DRIVER` | No | `database` | Session storage driver | | `CACHE_STORE` | No | `database` | Cache storage driver | | `QUEUE_CONNECTION` | No | `database` | Queue driver | | `MAIL_MAILER` | No | `log` | Mail driver (`smtp` for production) | | `MAIL_HOST` | No | `127.0.0.1` | SMTP server hostname | | `MAIL_PORT` | No | `2525` | SMTP port | | `MAIL_USERNAME` | No | `null` | SMTP username | | `MAIL_PASSWORD` | No | `null` | SMTP password | | `MAIL_FROM_ADDRESS` | No | `hello@example.com` | Sender email address | | `MAIL_FROM_NAME` | No | `${APP_NAME}` | Sender display name | | `FIREBASE_PROJECT_ID` | Yes | — | Firebase project identifier | | `FIREBASE_CREDENTIALS` | Yes | — | Path to Firebase credentials JSON | | `FCM_TOPIC_*` | No | See defaults | FCM notification topic names | --- ## Docker Compose Configuration The stack is defined in `docker-compose.yml` and consists of four services on a shared `tckdev_net` network: ### Services | Service | Image | Container | Port | Description | |---|---|---|---|---| | `app` | Custom (`Dockerfile`) | `tckdev-app` | 9000 (internal) | PHP-FPM 8.2 application | | `postgres` | `postgres:16` | `tckdev-db` | `5432:5432` | PostgreSQL database | | `web` | `nginx:stable-alpine` | `tckdev-web` | `80:80` | Nginx reverse proxy | | `pgadmin` | `dpage/pgadmin4` | `tckdev-pgAdmin` | `5050:80` | pgAdmin database manager | ### Volumes **Named volumes:** - `pgdata` -- PostgreSQL data persistence (`/var/lib/postgresql/data`) - `pgadmin_data` -- pgAdmin session and settings **Bind mounts:** - `./src:/var/www/html` -- Application source (mounted on both `app` and `web`) - `./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf` -- Nginx config (on `web`) - `./backup:/backups` -- Backup directory (on `pgadmin`) ### App Container Environment The `app` service passes these environment variables to control startup behavior: | Variable | Default | Description | |---|---|---| | `RUN_MIGRATIONS` | `true` | Run `php artisan migrate --force` on boot | | `RUN_SEEDER` | `true` | Run `php artisan db:seed --force` on boot | | `ADMIN_EMAIL` | `${ADMIN_EMAIL:-admin@example.com}` | Admin email for `DatabaseSeeder` | | `ADMIN_PASSWORD` | `${ADMIN_PASSWORD:-admin123}` | Admin password for `DatabaseSeeder` | ### Entrypoint The custom entrypoint (`docker/entrypoint.sh`) runs on every container start and performs: 1. Copies `.env.example` to `.env` if no `.env` exists 2. Runs `composer install` if `vendor/` is missing 3. Runs `npm install` if `node_modules/` is missing 4. Runs `npm run build` if `public/build/` is missing 5. Runs database migrations if `RUN_MIGRATIONS=true` 6. Runs database seeder if `RUN_SEEDER=true` 7. Caches config, routes, and views ### Health Check PostgreSQL has a health check (`pg_isready`) with 5-second intervals. Both `app` and `pgadmin` wait for PostgreSQL to be healthy before starting (`depends_on` with `condition: service_healthy`). --- ## Nginx Configuration Located at `docker/nginx/default.conf`. Key settings: - **Document root:** `/var/www/html/public` - **FastCGI pass:** `app:9000` (PHP-FPM on the `app` service) - **Security headers:** `X-Frame-Options: SAMEORIGIN`, `X-XSS-Protection: 1; mode=block`, `X-Content-Type-Options: nosniff` - **Laravel rewriting:** `try_files $uri $uri/ /index.php?$query_string` (standard Laravel URL rewriting) - **Hidden files:** Access to dotfiles (except `.well-known`) is denied --- ## Laravel Configuration ### Application Settings - **HTTPS enforcement:** `URL::forceScheme('https')` is called in `AppServiceProvider::boot()` (`src/app/Providers/AppServiceProvider.php`) - **Timezone:** `Asia/Kuala_Lumpur` (set in `src/config/app.php`) - **Locale:** `en` (default), with fallback locale also `en` ### Middleware Registered in `src/bootstrap/app.php`: | Alias | Class | Group | Description | |---|---|---|---| | `admin` | `AdminMiddleware` | Alias | Protects admin-only routes | | — | `LocalizationMiddleware` | `web` (appended) | Handles language/locale switching | ### Session, Cache, and Queue All three subsystems use the `database` driver by default, storing data in the PostgreSQL database. No external cache or queue server is required. ### Mail In production, mail is sent via SMTP through Gmail (`smtp.gmail.com:587`). In local development, the `log` mailer is used (emails are written to the log file instead of being sent). --- ## External Services ### Firebase Cloud Messaging (FCM) Used for push notifications (rainfall warnings, rainfall danger, water level alerts, water level danger). Configuration requires: - `FIREBASE_PROJECT_ID` -- The Firebase project ID - `FIREBASE_CREDENTIALS` -- Path to the service account JSON key file (stored in `storage/app/firebase/`) - `FCM_TOPIC_*` variables -- Topic names for each notification type ### FTP (sidesdecode.py) The `autoscript/sidesdecode.py` script connects to an external FTP server to download station data files. It reads `FTP_SERVER`, `FTP_USERNAME`, and `FTP_PASSWORD` from environment variables, falling back to defaults if not set. ### PostgreSQL Runs as a Docker container using the official `postgres:16` image. Connection credentials are shared between the root `.env` and `src/.env` via variable interpolation (`${POSTGRES_DB}`, `${POSTGRES_USER}`, `${POSTGRES_PASSWORD}`).