# Go-live load tuning (Top Up)

Nginx / PHP-FPM / OPcache were raised for multi-outlet POS (Top Up + Lena + Express).  
Image defaults live under `kedebah-commerce-deploy/docker/common/` and `.env.example`.

## What changed in the deploy repo

| Layer | Change |
|-------|--------|
| PHP-FPM | Defaults: finance **96**, commerce **32**, auth **32**, onboarding **24**; listen backlog **4096**; terminate timeout **180s** |
| App nginx | FastCGI keepalive **64**, listen backlog **4096**, read/send timeout **180s** |
| Edge nginx | `worker_connections` **16384**, proxy timeouts **180s** |
| PHP | `max_execution_time` / `max_input_time` **180**, `max_input_vars` **10000** |
| OPcache | **384M** + JIT **128M**, `validate_timestamps=0` (restart on deploy) |

## Apply on the server (required)

FPM counts come from **live `.env`**, not only image defaults. Nginx/php/opcache need a **rebuild**.

```bash
cd /var/www/html/KEDEBAH/kedebah-commerce-deploy

# Edit .env — set at least:
# FINANCE_FPM_MAX_CHILDREN=96
# COMMERCE_FPM_MAX_CHILDREN=32
# AUTH_FPM_MAX_CHILDREN=32
# ONBOARDING_FPM_MAX_CHILDREN=24
# PHP_FPM_MAX_REQUESTS=1000
# REDIS_MAXMEMORY=2gb

docker compose build finance commerce auth onboarding edge \
  finance-worker finance-scheduler
docker compose up -d

# Confirm finance pool
docker compose exec finance sh -lc \
  'grep -E "^pm\.(max_children|start_servers|max_spare)" /usr/local/etc/php-fpm.d/zz-www.conf'
docker compose exec finance sh -lc 'curl -s http://127.0.0.1/fpm-status'
```

Watch `listen queue` / `max children reached` on `/fpm-status`. If children are constantly maxed, raise finance further (e.g. 112) **only if RAM and PgBouncer allow**.

## PgBouncer (do this — DB is the real limit)

With ~216 PHP workers + queue workers, expect **250–320** possible DB clients.

In PgBouncer (host):

```ini
pool_mode = transaction
max_client_conn = 600
default_pool_size = 60
# optional per-user overrides for the Kedebah role
```

`DB_PORT` in compose `.env` must point at **PgBouncer** (e.g. `6432`), not Postgres directly.

Reload PgBouncer after edits, then:

```bash
# example — adjust to your install
sudo systemctl reload pgbouncer
# or: psql -p 6432 -U pgbouncer pgbouncer -c "SHOW CONFIG;"
```

## Host nginx (if it terminates TLS in front of edge)

If `EDGE_PUBLISH=127.0.0.1:8080:80` and host nginx proxies to it, align timeouts/body size:

```nginx
client_max_body_size 72M;
proxy_read_timeout 180s;
proxy_send_timeout 180s;
proxy_connect_timeout 10s;
```

Then `sudo nginx -t && sudo systemctl reload nginx`.

## Optional: more queue throughput

```bash
docker compose up -d --scale finance-worker=2
```

## Optional: second finance API replica (needs free RAM)

```bash
docker compose up -d --scale finance=2
```

## Quick health after open of business

```bash
docker compose exec finance sh -lc 'curl -s http://127.0.0.1/fpm-status'
docker stats --no-stream
free -h
```

Healthy signs: spare FPM workers available, no sustained `max children reached`, Redis under `REDIS_MAXMEMORY`, PgBouncer not saturating `default_pool_size` with long waits.
