Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ All notable changes to this project will be documented in this file.
- Switched image build pipeline to GHCR with multi-arch layer caching.
- Aligned the nginx image env-var contract: split `NGINX_FPM_SERVICE` and
`NGINX_FPM_PORT`, raised upload cap and trusted-proxy CIDR defaults.
- Documented the 3.x operator-facing image-deployment contract in
`UPGRADE.md` (full `APP_*` → unprefixed rename list, `env_file:` pattern,
runtime-tuning surfaces).
- Allowed same-origin iframe embedding so the admin's screen/playlist
preview and fullscreen slide view work (#390).
- Image build now writes `public/release.json` so the client's
Expand Down
145 changes: 140 additions & 5 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,147 @@ docker compose exec phpfpm bin/console app:utils:convert-config-json-to-env --ty

#### 2.1 - Rename environment variables

Rename the following .env variables in `.env.local`:
In 3.x the compose stack carries no `APP_*` prefix translation — variable
names in `.env.local` must match the Symfony names exactly. Every
`APP_X` variable from the previous 2.x `.env.docker.local` is renamed
to `X`, with the **exception of `APP_ENV` and `APP_SECRET`** which are
Symfony-defined and keep their prefix.

The full rename list:

```text
APP_TRUSTED_PROXIES → TRUSTED_PROXIES
APP_DATABASE_URL → DATABASE_URL
APP_CORS_ALLOW_ORIGIN → CORS_ALLOW_ORIGIN
APP_DEFAULT_DATE_FORMAT → DEFAULT_DATE_FORMAT
APP_ACTIVATION_CODE_EXPIRE_INTERVAL → ACTIVATION_CODE_EXPIRE_INTERVAL
APP_KEY_VAULT_SOURCE → KEY_VAULT_SOURCE
APP_KEY_VAULT_JSON → KEY_VAULT_JSON
APP_TRACK_SCREEN_INFO → TRACK_SCREEN_INFO
APP_TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS → TRACK_SCREEN_INFO_UPDATE_INTERVAL_SECONDS

APP_JWT_SECRET_KEY → JWT_SECRET_KEY
APP_JWT_PUBLIC_KEY → JWT_PUBLIC_KEY
APP_JWT_PASSPHRASE → JWT_PASSPHRASE
APP_JWT_TOKEN_TTL → JWT_TOKEN_TTL
APP_JWT_SCREEN_TOKEN_TTL → JWT_SCREEN_TOKEN_TTL
APP_JWT_REFRESH_TOKEN_TTL → JWT_REFRESH_TOKEN_TTL
APP_JWT_SCREEN_REFRESH_TOKEN_TTL → JWT_SCREEN_REFRESH_TOKEN_TTL

APP_REDIS_CACHE_PREFIX → REDIS_CACHE_PREFIX
APP_REDIS_CACHE_DSN → REDIS_CACHE_DSN

APP_HTTP_CLIENT_TIMEOUT → HTTP_CLIENT_TIMEOUT
APP_HTTP_CLIENT_MAX_DURATION → HTTP_CLIENT_MAX_DURATION
APP_HTTP_CLIENT_LOG_LEVEL → HTTP_CLIENT_LOG_LEVEL

APP_INTERNAL_OIDC_METADATA_URL → INTERNAL_OIDC_METADATA_URL
APP_INTERNAL_OIDC_CLIENT_ID → INTERNAL_OIDC_CLIENT_ID
APP_INTERNAL_OIDC_CLIENT_SECRET → INTERNAL_OIDC_CLIENT_SECRET
APP_INTERNAL_OIDC_REDIRECT_URI → INTERNAL_OIDC_REDIRECT_URI
APP_INTERNAL_OIDC_LEEWAY → INTERNAL_OIDC_LEEWAY
APP_INTERNAL_OIDC_CLAIM_NAME → INTERNAL_OIDC_CLAIM_NAME
APP_INTERNAL_OIDC_CLAIM_EMAIL → INTERNAL_OIDC_CLAIM_EMAIL
APP_INTERNAL_OIDC_CLAIM_GROUPS → INTERNAL_OIDC_CLAIM_GROUPS

APP_EXTERNAL_OIDC_METADATA_URL → EXTERNAL_OIDC_METADATA_URL
APP_EXTERNAL_OIDC_CLIENT_ID → EXTERNAL_OIDC_CLIENT_ID
APP_EXTERNAL_OIDC_CLIENT_SECRET → EXTERNAL_OIDC_CLIENT_SECRET
APP_EXTERNAL_OIDC_REDIRECT_URI → EXTERNAL_OIDC_REDIRECT_URI
APP_EXTERNAL_OIDC_LEEWAY → EXTERNAL_OIDC_LEEWAY
APP_EXTERNAL_OIDC_HASH_SALT → EXTERNAL_OIDC_HASH_SALT
APP_EXTERNAL_OIDC_CLAIM_ID → EXTERNAL_OIDC_CLAIM_ID
APP_OIDC_CLI_REDIRECT → OIDC_CLI_REDIRECT

APP_CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT → CALENDAR_API_FEED_SOURCE_LOCATION_ENDPOINT
APP_CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT → CALENDAR_API_FEED_SOURCE_RESOURCE_ENDPOINT
APP_CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT → CALENDAR_API_FEED_SOURCE_EVENT_ENDPOINT
APP_CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS → CALENDAR_API_FEED_SOURCE_CUSTOM_MAPPINGS
APP_CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS → CALENDAR_API_FEED_SOURCE_EVENT_MODIFIERS
APP_CALENDAR_API_FEED_SOURCE_DATE_FORMAT → CALENDAR_API_FEED_SOURCE_DATE_FORMAT
APP_CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE → CALENDAR_API_FEED_SOURCE_DATE_TIMEZONE
APP_CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS → CALENDAR_API_FEED_SOURCE_CACHE_EXPIRE_SECONDS

APP_EVENTDATABASE_API_V2_CACHE_EXPIRE_SECONDS → EVENTDATABASE_API_V2_CACHE_EXPIRE_SECONDS

APP_ADMIN_REJSEPLANEN_APIKEY → ADMIN_REJSEPLANEN_APIKEY
APP_ADMIN_SHOW_SCREEN_STATUS → ADMIN_SHOW_SCREEN_STATUS
APP_ADMIN_TOUCH_BUTTON_REGIONS → ADMIN_TOUCH_BUTTON_REGIONS
APP_ADMIN_LOGIN_METHODS → ADMIN_LOGIN_METHODS
APP_ADMIN_ENHANCED_PREVIEW → ADMIN_ENHANCED_PREVIEW

APP_CLIENT_LOGIN_CHECK_TIMEOUT → CLIENT_LOGIN_CHECK_TIMEOUT
APP_CLIENT_REFRESH_TOKEN_TIMEOUT → CLIENT_REFRESH_TOKEN_TIMEOUT
APP_CLIENT_RELEASE_TIMESTAMP_INTERVAL_TIMEOUT → CLIENT_RELEASE_TIMESTAMP_INTERVAL_TIMEOUT
APP_CLIENT_SCHEDULING_INTERVAL → CLIENT_SCHEDULING_INTERVAL
APP_CLIENT_PULL_STRATEGY_INTERVAL → CLIENT_PULL_STRATEGY_INTERVAL
APP_CLIENT_COLOR_SCHEME → CLIENT_COLOR_SCHEME
APP_CLIENT_DEBUG → CLIENT_DEBUG
```

The `os2display-docker-server` repo provides `task env:migrate`, which
performs this rename automatically: it reads a 2.x `.env.docker.local`
and writes a 3.x-shaped `.env.local`. Use it as the recommended
migration path:

```shell
# In your os2display-docker-server checkout, on the 3.0 branch:
task env:migrate
task env:diff # review the result against the canonical example
```

#### 2.2 - Adopt the new operator-facing image-deployment contract

Production deployments now use the GHCR-published images
(`ghcr.io/os2display/display-api-service` and
`ghcr.io/os2display/display-api-service-nginx`) and follow an `env_file:`
pattern in the compose stack.

##### Bootstrap `.env.local` from the image

The image ships a self-documenting `.env` at `/var/www/html/.env` that
lists every Symfony env variable the application consumes, with a
one-line description per variable. Use it as the starting point for
your operator-host `.env.local`:

```shell
docker run --rm ghcr.io/os2display/display-api-service:<tag> \
cat /var/www/html/.env > .env.local
```

Then edit `.env.local` to set the required values for your environment:

- `APP_ENV=prod`
- `APP_SECRET=<generated-secret>`
- `JWT_PASSPHRASE=<generated-passphrase>`
- `DATABASE_URL=<connection-string>`
- `CORS_ALLOW_ORIGIN=<your-allowed-origin-regex>`
- OIDC provider settings (`INTERNAL_OIDC_*` and/or `EXTERNAL_OIDC_*`)

##### Reference `.env.local` from compose via `env_file:`

```yaml
services:
api:
image: ghcr.io/os2display/display-api-service:<tag>
env_file:
- .env.local
```

The `os2display-docker-server` compose stack does this for you. See its
`UPGRADE.md` for full operator migration steps.

##### nginx and PHP-FPM runtime tuning

OS-level / runtime knobs are independent of the Symfony env surface and
are passed to their respective images via compose `environment:`:

- From `APP_DEFAULT_DATE_FORMAT` to `DEFAULT_DATE_FORMAT`
- From `APP_ACTIVATION_CODE_EXPIRE_INTERVAL` to `ACTIVATION_CODE_EXPIRE_INTERVAL`
- From `APP_KEY_VAULT_SOURCE` to `KEY_VAULT_SOURCE`
- From `APP_KEY_VAULT_JSON` to `KEY_VAULT_JSON`
- nginx: `NGINX_PORT`, `NGINX_FPM_SERVICE`, `NGINX_FPM_PORT`,
`NGINX_MAX_BODY_SIZE`, `NGINX_SET_REAL_IP_FROM`, `NGINX_WEB_ROOT`
(defaults in `infrastructure/nginx/Dockerfile`).
- PHP-FPM: `PHP_MEMORY_LIMIT`, `PHP_MAX_EXECUTION_TIME`,
`PHP_POST_MAX_SIZE`, `PHP_UPLOAD_MAX_FILESIZE`, `PHP_PM_*`,
`PHP_OPCACHE_*` (consumed by the `itkdev/php8.4-fpm` base image).

#### 3 - Consolidate Doctrine migrations

Expand Down