# Deploy to the JHASI server

This application runs on a PHP-capable Linux or Windows server with MySQL. The server does not need Node.js, jQuery, Composer or a build step. Bootstrap, icons and Leaflet are already included under `public/assets/vendor/`.

## 1. Prepare the server

Use a maintained PHP 8.4 or newer release with `pdo_mysql`, `mbstring`, `sodium`, `fileinfo` and `gd`, and MySQL 8.4 LTS. MySQL 8.0.16+ supports the required enforced CHECK constraints. MariaDB has not been validated for this package.

Recommended PHP values are in `deploy/php.ini.example`: 10 MB per upload, 25 MB total POST limit, 256 MB memory and a 90-second request limit. Align the web server's upload limit with PHP. Configure a private PHP session directory and restrict read access to it.

Install the application at a private path such as `/var/www/jhasi-assessment`. Set the website's document root to **`/var/www/jhasi-assessment/public`**. Never expose the project root: it contains configuration, database scripts and application code.

For Linux, adapt `deploy/nginx.conf.example` or `deploy/apache.conf.example`. These are examples: replace hostname, paths, certificate locations and the PHP socket with actual JHASI settings. The PHP built-in development server is for local testing only.

For Windows IIS:

- Install PHP through FastCGI and enable the listed extensions.
- Set the site's physical path to the `public` directory. That directory contains `web.config` with request-size limits and directory browsing disabled.
- Configure an HTTPS binding and redirect HTTP to HTTPS at IIS.
- Grant the site's application-pool identity read access to the code and configuration, and modify access only to private `storage` and its PHP session/upload temporary directories.
- Leave `environment` as `production` and `session_secure` as `true` in the application configuration.

The application checks the server's HTTPS flag. With a TLS-terminating reverse proxy, configure the trusted web server/FastCGI boundary to set `HTTPS=on` for the protected HTTPS virtual host. Do not trust arbitrary client `X-Forwarded-Proto` headers or disable secure cookies to work around proxy setup.

## 2. Create the database

Using a database administrator on a **new, empty** installation:

```sh
mysql -u root -p < database/schema.sql
```

The schema creates `jhasi_assessment`, its tables, constraints and the immutable-assessment trigger. Use `utf8mb4` throughout. This is an initial schema, not an upgrade migration; do not import it over an existing installation.

Edit the password in `database/grants.example.sql`, then execute it through the database administrator. It creates `jhasi_app` with table-scoped access. The application account must not be root and must not have `DROP`, `ALTER`, `DELETE`, `TRIGGER`, or user-management permissions. The trigger must be created by the deployment database administrator before switching to the limited account.

The example uses `jhasi_app@localhost`. For a separate database host, provision the correct restricted client host, use a private network and verified database TLS at the infrastructure layer. This package is configured and tested for a local MySQL connection; a remote database needs a server-specific TLS configuration review.

### Upgrade from the earlier assessment package

For an existing installation, follow [docs/MEAL-AND-INCENTIVES.md](docs/MEAL-AND-INCENTIVES.md). Back up and pause writes, run `database/migrations/002_meal_incentives_hours.sql` once, apply `002_grants.sql`, then replace code while preserving configuration/key/storage. Never run the upgrade after installing this version’s full schema. Earlier work is backfilled at the agreed initial rates and explicitly marked as legacy.

## 3. Configure secrets and storage

Copy `config/config.example.php` to `config/local.php`. Set:

- `db_dsn`: the local MySQL hostname, port and database.
- `db_user` and `db_password`: the limited account from step 2.
- `app_key`: the output of `php bin/console.php key`.
- `storage_path`: a private writable directory outside `public/`.
- `environment`: `production`; `session_secure`: `true`.
- `timezone`: `Asia/Amman` unless JHASI requires another display date timezone.
- `no_assistance_points`: leave **`null`** until the programme policy is confirmed.
- `assessment_target` and `kit_target`: optional approved programme targets; `0` means not configured.

Store a protected backup of the encryption key separately from database and file backups. **Do not regenerate or replace this key after collecting data.** It encrypts data and creates the duplicate-detection indexes; losing it makes records unreadable and replacing it requires a planned migration.

Make code read-only to the web process. On Linux, for an installation owned by a deployment account with PHP running as `www-data`, appropriate ownership and modes include:

```sh
chown deploy:www-data config/local.php
chmod 640 config/local.php
install -d -o www-data -g www-data -m 700 storage
```

Adapt account names to the actual server. Do not use world-writable permissions. On Windows, use the corresponding NTFS ACLs. Keep production household documents off unmanaged desktop sync folders.

Run:

```sh
php bin/console.php check
```

It checks required extensions, the encryption key, database connectivity and storage writability. It does not verify the external web server, HTTPS binding or complete operational security.

## 4. Create the first administrator

There is no public registration page and no default production password. The CLI reads the initial password from an environment variable so it does not appear in command arguments. On Bash:

```sh
read -r -s -p 'Temporary administrator password: ' JHASI_INITIAL_PASSWORD
export JHASI_INITIAL_PASSWORD
php bin/console.php create-user admin@your-jhasi-domain.org "Programme administrator" admin
unset JHASI_INITIAL_PASSWORD
```

Choose at least 12 characters (maximum 72 UTF-8 bytes). For PowerShell, set `JHASI_INITIAL_PASSWORD` using the server's approved secret-entry method and run the same PHP command; clear the environment variable afterwards. Do not put real passwords in deployment scripts, shell history or this document.

The administrator must change the temporary password on first login, then create named individual team accounts from **Team access**. Assign distribution accounts exactly one of `Zaatari Camp` or `Sweime / Al-Ghor`. Administrators can disable accounts and reset temporary passwords, which invalidate existing sessions. Share temporary passwords through JHASI's approved private channel.

Create a MEAL monitoring account as well. In **Programme settings**, verify assessment rate **2.120 JOD**, handover rate **1.420 JOD**, and daily hours **09:00–15:00 Asia/Amman**. Administrators retain outside-hours access. All other roles are checked at login and on every work/data request. Rate changes affect future events only. Synchronize the server clock.

## 5. Document scanning and maps

Files undergo MIME validation, size limits and image decoding/re-encoding; documents are stored encrypted outside the public directory. PDF downloads are forced attachments. For malware scanning, install and maintain ClamAV/clamdscan and set `scanner_path` to its absolute executable path. The PHP service must be allowed to execute it and the scanner must be able to read PHP temporary upload files. If configured scanning fails or detects a problem, the upload is rejected. Set the scanner's own timeout to bound scan duration. Empty `scanner_path` means no antivirus scan is performed.

Browser location capture requires HTTPS and the assessor's location permission. The form records browser-reported coordinates, accuracy and capture time. A map fallback records manually selected coordinates and a reason. Neither browser GPS nor a map selection cryptographically proves the visit; the review team should check improbable or low-accuracy locations.

Map tiles use `https://tile.openstreetmap.org` only when opening the map. That service sees normal tile requests and the requesting IP. To use JHASI-hosted tiles, change the tile URL in `public/assets/app.js` and the allowed `img-src` host in `app/bootstrap.php`, preserving map attribution required by the tile provider.

## 6. Acceptance and operations

Before actual household visits, test HTTPS login from a real assessment phone, location permission, the camera/file picker, a sample PDF and photo upload, a review decision, both distribution scopes and receiving-note closure. Remove or segregate any server acceptance-test records before real collection starts; the application intentionally has no record-deletion UI.

Back up the MySQL database, private storage and configuration key as one consistent recovery set. Prefer pausing writes briefly while taking a consistent database and file backup. Restrict and encrypt backups, test restoration to an isolated server, and apply JHASI's retention policy to records, files, audit events and backups. No retention period is invented by this application.

Keep PHP, MySQL, web server, operating system, Bootstrap, icons and Leaflet patched. Review failed logins and application incident IDs in server logs. The UI shows the latest 200 audit events; all audit rows remain in the database. Schedule cleanup of expired `login_limits` buckets through a DBA-controlled process (for example, buckets older than 30 days), not by granting the application extra privileges.

For upgrades, back up first, preserve `config/local.php`, the encryption key and private storage, and review database changes. This version does not provide a destructive reset command or an automatic schema-upgrade mechanism.
