# Deploying the PHP API to shared cPanel hosting

The API in `backend-php/` is a Laravel 12 application. It runs on any cPanel host that offers
PHP 8.2 or newer and a MySQL or MariaDB database, which is standard. The desktop and mobile apps
only need its public address; nothing else in them changes.

## 1. Check the host

In cPanel:

- **MultiPHP Manager** (or *Select PHP Version*): set the domain to PHP 8.2, 8.3 or 8.4.
  Enable these extensions if they are not already on: `pdo_mysql`, `mbstring`, `openssl`,
  `curl`, `fileinfo`, `tokenizer`, `xml`, `ctype`, `bcmath`, `intl`.
- **MySQL Databases**: create a database and a user with all privileges on it. Note the three
  names cPanel gives you (they are prefixed with your account name).
- **Terminal** or SSH access makes the steps below much easier. Without it, every command
  can be run through a one-off cron job, but SSH is the sane route.

## 2. Put the code on the server

Laravel's `public/` folder is the only folder the web server may serve. Keep the rest of the
application **outside** the web root. The clean way is a subdomain, e.g. `api.example.com`:

1. Upload or `git clone` the repository to `~/task-manager` (anywhere outside `public_html`).
2. In cPanel **Domains**, create the subdomain `api.example.com` and set its document root to
   `/home/<account>/task-manager/backend-php/public`.
3. cPanel's AutoSSL issues the HTTPS certificate for the subdomain within a few minutes.

If the host does not let you change a document root, put this `.htaccess` in the subdomain's
default folder instead, pointing at the real `public/` folder:

```apache
RewriteEngine On
RewriteRule ^(.*)$ /home/<account>/task-manager/backend-php/public/$1 [L]
```

## 3. Install dependencies

From the `backend-php` folder on the server:

```bash
composer install --no-dev --optimize-autoloader
```

If the host has no Composer, run `composer install --no-dev --optimize-autoloader` locally and
upload the resulting `vendor/` folder along with the code (it is git-ignored on purpose).

## 4. Configure

```bash
cp .env.example .env
php artisan key:generate
```

Then edit `.env`:

| Setting | Value on the server |
|---|---|
| `APP_ENV` | `production` |
| `APP_DEBUG` | `false` |
| `APP_URL` | `https://api.example.com` |
| `LOG_LEVEL` | `warning` |
| `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD` | the names from step 1 |
| `JWT_SIGNING_KEY` | output of `php -r "echo bin2hex(random_bytes(32));"`, kept secret |
| `AUTH_ENABLE_DEV_LOGIN` | `false` (the app refuses to start in production otherwise) |
| `GOOGLE_CLIENT_IDS` | the desktop and web client ids from `docs/sign-in-setup.md`, comma-separated |
| `MICROSOFT_CLIENT_IDS` | empty until Microsoft sign-in is set up |

Create the tables and cache the configuration:

```bash
php artisan migrate --force
php artisan config:cache
php artisan route:cache
```

Re-run the two `cache` commands after every change to `.env` or to the code.

## 5. Check it

- `https://api.example.com/` answers `{"name":"Task Manager API","status":"ok"}`.
- `https://api.example.com/up` answers 200.
- `https://api.example.com/api/tasks` without a token answers 401 with a JSON body.

## 6. Point the apps at it

- Desktop: `ApiBaseUrl` in `appsettings.json` next to `TaskManager.Desktop.exe`.
- Mobile: `API_BASE_URL` in `mobile/dart_defines.json`, then rebuild the APK.

## Housekeeping

- **Updates**: `git pull`, `composer install --no-dev --optimize-autoloader`,
  `php artisan migrate --force`, `php artisan config:cache`, `php artisan route:cache`.
- **Logs** are in `storage/logs/laravel.log`. Make sure `storage/` and `bootstrap/cache/` are
  writable by the PHP user (cPanel's defaults are fine).
- **Backups**: cPanel's backup tool covers the database; nothing else holds state.
- **Rate limit**: 600 requests per minute per IP address, set in `AppServiceProvider`.
