# Deployment

Deployment is done **by the developer, manually, on the server**. There is no CI/CD pipeline and no automated
deploy from a local machine. The Docker setup in this repository is for local development only.

## Server requirements

- PHP 8.3 CLI + FPM with `json`, `curl`, `gd`, `mbstring`, `intl`, `fileinfo`, `simplexml`, `yaml`, `zip`
- MariaDB 10.11 (what production runs; the local environment pins 10.6)
- Redis (or Memcached, or fall back to file cache)
- nginx or Apache with the document root at `web/`
- `optipng` and `jpegoptim` for the image optimization cron
- Composer
- Node.js + npm **only if** assets are built on the server; normally `web/build/` is committed and deployed as is

## Configuration

`env.php` is **not in Git** and lives only on the server. Derive it from `env.example.php` and set at minimum:

| Constant group | Notes |
|----------------|-------|
| `YII_ENV` | `'prod'` (or `'test'` on the staging site) |
| `APP_URL` | the real base URL with `https://` and a trailing slash |
| `DB_*` | server database credentials |
| `CACHE_REDIS_*` | server Redis connection |
| `MAILER_*` | real SMTP host, port, credentials, encryption |
| `REQUEST_COOKIE_VALIDATION_KEY` | a unique random value per environment |
| `LOG_EMAIL_*` | error mail recipients and the subject naming the environment |
| `ANTHROPIC_API_KEY` | required if AI translation runs on the server |
| `LEGACY_DB_NAME` | leave empty — the Drupal re-import runs locally, not here |
| `TELL_API_KEY`, `APP_GATE_SYNC_ENABLED` | required for the gate sync; `APP_GATE_SYNC_FAKE` must be `false` |
| `BILLINGO_SEND_EMAIL` | whether Billingo mails the invoice to the customer |
| `DEV_DEBUG_ENABLED` | must be `false` |
| `USER_DEFAULT_ADMIN_PASSWORD` | change from the default |

`LEGACY_DB_NAME` is only needed where the Drupal re-import runs — normally the developer's machine, not
the server. Leaving it empty disables every `import/*` command.

`robots.txt` is generated: it emits `Allow: /` **only** when `APP_URL` is exactly `https://raktar24.hu/`
([`controllers/SiteController.php:96`](../controllers/SiteController.php)). Every other environment — staging
included — is automatically disallowed.

## Writable directories

```
runtime
web/assets
web/build
web/contents
```

`web/contents/` holds all uploaded files and generated image versions — it must be **backed up** and must
survive deployments.

## Deploy procedure

Sample scripts: [`deploy-samples/deploy-prod.sh`](deploy-samples/deploy-prod.sh),
[`deploy-samples/deploy-test.sh`](deploy-samples/deploy-test.sh). Copy one to the server, adjust the target
directory and PHP path.

The sequence is:

```shell
php ./yii deploy/flush-cache     # before: the schema cache must not be stale
git pull origin master
php ./yii migrate
php ./yii deploy/flush-cache     # after: reference data and widget output may have changed
```

The cache is flushed **twice** on purpose. The first flush clears the database schema cache so migrations see
the current schema; the second clears application data caches so the frontend picks up the new state.

Composer is only needed when `composer.lock` changed:

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

`--no-dev` is not optional: PHPUnit and the debug toolbar are dev dependencies and have no business on the
server. **Tests are never run on production** — see [TESTING.md](TESTING.md).

**Assets are never built on the server** — there is no Node there. `web/build/` arrives with the `git pull`,
production-built and committed before the push. See [DEVELOPMENT.md](DEVELOPMENT.md#assets).

## After a deploy

Run these when the change requires it:

| Situation | Command |
|-----------|---------|
| searchable fields or languages changed | `php ./yii search-index/build` |
| new content needs translating | `php ./yii translate/model <Model>` |
| a new location's gate needs registering | `php ./yii gate-sync/register <locationId>` |

Check `runtime/logs/` and the configured error-mail recipients afterwards. The TELL integration keeps its own
log at `runtime/logs/tell-api.log`, controlled by `TELL_API_LOG_MODE`.

## Cron

Set up the scheduled jobs — see [CRON.md](CRON.md). Five of them are required for a fully working
installation: image optimization, payment generation, invoicing, AI translation and the gate sync.

## Rollback

`git checkout <previous-commit>` plus a cache flush restores the code. **Migrations are not automatically
reversible** — they rely on `SchemaHelper` and the models' own schema declarations, so verify a `down` path
exists before relying on one. Take a database dump before deploying a migration.
