docs: rewrite all documentation to reflect current state
- Remove adminer references (service was removed) - Remove mermaid diagrams (ASCII only) - Remove hardcoded credentials (use env var references) - Update all Docker references to 4-container setup (app, postgres, web, pgadmin) - Document env-based admin credentials (ADMIN_EMAIL/ADMIN_PASSWORD) - Document parameterized queries (SQL injection fixed) - Document FCM topic routing by stationtype+level - Document siren stationtype=3 fix in sidesdecode.py - Document idempotent seeder (firstOrCreate) - Document reverse proxy setup in deployment guide - Remove Makefile references (Docker Compose only)
This commit is contained in:
@@ -1,119 +1,179 @@
|
||||
# Configuration Reference
|
||||
<!-- generated-by: gsd-doc-writer -->
|
||||
|
||||
## Environment Variables
|
||||
# Configuration
|
||||
|
||||
### Application Settings
|
||||
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.
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `APP_NAME` | `SIDES` | Application name |
|
||||
| `APP_ENV` | `local` | Environment (local/production) |
|
||||
| `APP_KEY` | (generated) | Encryption key |
|
||||
| `APP_DEBUG` | `true` | Show debug errors |
|
||||
| `APP_URL` | `https://sides.tck.com.my` | Application URL |
|
||||
| `APP_LOCALE` | `en` | Default language |
|
||||
| `APP_TIMEZONE` | `Asia/Kuala_Lumpur` | Timezone (set in config/app.php) |
|
||||
---
|
||||
|
||||
### Database
|
||||
## Environment Variables Overview
|
||||
|
||||
| Variable | Value | Description |
|
||||
|----------|-------|-------------|
|
||||
| `DB_CONNECTION` | `pgsql` | Database driver |
|
||||
| `DB_HOST` | `192.168.0.211` | Database host (external IP) |
|
||||
| `DB_PORT` | `5432` | PostgreSQL port |
|
||||
| `DB_DATABASE` | `sides_db` | Database name (via `POSTGRES_DB`) |
|
||||
| `DB_USERNAME` | `tck` | Database user (via `POSTGRES_USER`) |
|
||||
| `DB_PASSWORD` | `projectdev##1` | Database password (via `POSTGRES_PASSWORD`) |
|
||||
### Root `.env` (Docker Compose)
|
||||
|
||||
### Docker-level Database
|
||||
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 | Value | Description |
|
||||
|----------|-------|-------------|
|
||||
| `POSTGRES_DB` | `tckdev` | Docker postgres database name |
|
||||
| `POSTGRES_USER` | `tck` | Docker postgres user |
|
||||
| `POSTGRES_PASSWORD` | `projectdev##1` | Docker postgres password |
|
||||
| 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 |
|
||||
|
||||
**Note**: There is a discrepancy — Docker `.env` creates database `tckdev` while Laravel `.env` connects to `sides_db` on an external host.
|
||||
### App `.env` (Laravel)
|
||||
|
||||
### Firebase / FCM
|
||||
Located at `src/.env`. Controls Laravel framework and application settings. See `src/.env.example` for the full list.
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `FIREBASE_PROJECT_ID` | `sides-b4abb` |
|
||||
| `FIREBASE_CREDENTIALS` | `storage/app/firebase/sides-b4abb-3604a7cf7584.json` |
|
||||
| `FCM_TOPIC_RAINFALL_WARNING` | `rainfall_warning` |
|
||||
| `FCM_TOPIC_RAINFALL_DANGER` | `rainfall_danger` |
|
||||
| `FCM_TOPIC_WATERLEVEL_ALERT` | `waterlevel_alert` |
|
||||
| `FCM_TOPIC_WATERLEVEL_DANGER` | `waterlevel_danger` |
|
||||
| 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 |
|
||||
|
||||
### Mail (SMTP)
|
||||
|
||||
| Variable | Value | Description |
|
||||
|----------|-------|-------------|
|
||||
| `MAIL_MAILER` | `smtp` | Mail driver |
|
||||
| `MAIL_HOST` | `smtp.gmail.com` | Gmail SMTP |
|
||||
| `MAIL_PORT` | `587` | SMTP port (TLS) |
|
||||
| `MAIL_USERNAME` | `sideskupang@gmail.com` | Gmail account |
|
||||
| `MAIL_PASSWORD` | `ipmu zifw bpmf fsyp` | Gmail App Password |
|
||||
| `MAIL_FROM_ADDRESS` | `sideskupang@gmail.com` | From address |
|
||||
| `MAIL_FROM_NAME` | `${APP_NAME}` | From name |
|
||||
|
||||
### Session & Cache
|
||||
|
||||
| Variable | Value | Description |
|
||||
|----------|-------|-------------|
|
||||
| `SESSION_DRIVER` | `database` | Session storage |
|
||||
| `SESSION_LIFETIME` | `120` | Session timeout (minutes) |
|
||||
| `CACHE_STORE` | `database` | Cache storage |
|
||||
| `QUEUE_CONNECTION` | `database` | Queue driver |
|
||||
---
|
||||
|
||||
## Docker Compose Configuration
|
||||
|
||||
### Networks
|
||||
The stack is defined in `docker-compose.yml` and consists of four services on a shared `tckdev_net` network:
|
||||
|
||||
- `tckdev_net` — Custom bridge network for all containers
|
||||
### 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
|
||||
|
||||
| Volume | Container | Purpose |
|
||||
|--------|-----------|---------|
|
||||
| `./src:/var/www/html` | app, web | Laravel application code |
|
||||
| `./docker/postgres/data:/var/lib/postgres/data` | postgres | PostgreSQL data |
|
||||
| `./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf` | web | Nginx config |
|
||||
| `./backup:/var/lib/pgadmin/storage/...` | pgadmin | pgAdmin backup storage |
|
||||
**Named volumes:**
|
||||
- `pgdata` -- PostgreSQL data persistence (`/var/lib/postgresql/data`)
|
||||
- `pgadmin_data` -- pgAdmin session and settings
|
||||
|
||||
### Ports
|
||||
**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`)
|
||||
|
||||
| Host Port | Container Port | Service |
|
||||
|-----------|---------------|---------|
|
||||
| 80 | 80 | Nginx (web) |
|
||||
| 5432 | 5432 | PostgreSQL |
|
||||
| 5050 | 80 | pgAdmin |
|
||||
| 6060 | 8080 | Adminer |
|
||||
### 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`:
|
||||
Located at `docker/nginx/default.conf`. Key settings:
|
||||
|
||||
- Root: `/var/www/html/public`
|
||||
- PHP processing via FastCGI to `app:9000`
|
||||
- Security headers: X-Frame-Options, X-XSS-Protection, X-Content-Type-Options
|
||||
- Laravel URL rewriting: `try_files $uri $uri/ /index.php?$query_string`
|
||||
- Hidden file access denied (except `.well-known`)
|
||||
- **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
|
||||
|
||||
### Middleware Registration
|
||||
### Application Settings
|
||||
|
||||
Registered in `bootstrap/app.php`:
|
||||
- **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`
|
||||
|
||||
- `admin` → `AdminMiddleware::class` (alias)
|
||||
- `LocalizationMiddleware` appended to web middleware group
|
||||
### Middleware
|
||||
|
||||
### HTTPS Forcing
|
||||
Registered in `src/bootstrap/app.php`:
|
||||
|
||||
`AppServiceProvider::boot()` calls `URL::forceScheme('https')` globally, making all generated URLs use HTTPS.
|
||||
| Alias | Class | Group | Description |
|
||||
|---|---|---|---|
|
||||
| `admin` | `AdminMiddleware` | Alias | Protects admin-only routes |
|
||||
| — | `LocalizationMiddleware` | `web` (appended) | Handles language/locale switching |
|
||||
|
||||
### Timezone
|
||||
### Session, Cache, and Queue
|
||||
|
||||
Set to `Asia/Kuala_Lumpur` in `config/app.php` (UTC+8, Malaysia Time).
|
||||
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
|
||||
|
||||
<!-- VERIFY: Firebase console URL and project configuration details -->
|
||||
|
||||
### 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.
|
||||
|
||||
<!-- VERIFY: FTP server address and directory structure -->
|
||||
|
||||
### 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}`).
|
||||
|
||||
Reference in New Issue
Block a user