# راهنمای دیپلوی ClinicPro روی لیارا (پلتفرم PHP)

دیپلوی بک‌اند Symfony روی **پلتفرم PHP لیارا** (نوع برنامه `php` هنگام «ساخت برنامه‌ی جدید»). اینجا داکری در کار نیست؛ لیارا کد را می‌گیرد، خودش `composer install` می‌زند و روی Apache + PHP-FPM سرو می‌کند.

> مسیر جایگزین (داکر) در [docs/deploy-liara.md](deploy-liara.md) است. **همزمان فقط یک مسیر** را نگه دار — هر دو از یک `liara.json` استفاده می‌کنند.

---

## نمای کلی

```
┌──────────────── Liara private network ─────────────────┐
│                                                        │
│  ┌──────────────────────────────┐   ┌──────────────┐   │
│  │  clinicpro-api  (PHP app)    │   │ MariaDB 11.8 │   │
│  │  • Apache + PHP-FPM (docroot │◄─►│  (managed)   │   │
│  │    = public/)  :80           │   └──────────────┘   │
│  │  • supervisor.conf:          │   ┌──────────────┐   │
│  │     worker-async             │◄─►│    Redis     │   │
│  │     worker-scheduler         │   │  (managed)   │   │
│  └──────────────────────────────┘   └──────────────┘   │
│   disks: jwt / uploads / var-uploads                   │
└────────────────────────────────────────────────────────┘
                  │ :80
                  ▼  https://<domain>
```

همهٔ پروسه‌ها (وب + هر دو worker) در **یک** کانتینر اجرا می‌شوند؛ workerها کانتینر جدا ندارند (برخلاف نسخهٔ docker-compose).

---

## فایل‌های دخیل (همه ساخته شده‌اند)

| فایل | نقش |
|---|---|
| [`liara.json`](../liara.json) | `platform: php`، `php.version: 8.2`، `documentRoot: public`، دیسک‌ها |
| [`public/.htaccess`](../public/.htaccess) | rewrite front-controller سیمفونی روی Apache |
| [`liara_pre_build.sh`](../liara_pre_build.sh) | قبل `composer install`: ساخت `.env` مینیمال prod |
| [`liara_pre_start.sh`](../liara_pre_start.sh) | قبل start: انتظار DB، تولید JWT، cache، migration |
| [`supervisor.conf`](../supervisor.conf) | دو worker مسنجر (`async` + `scheduler_default`) |
| [`liara_php.ini`](../liara_php.ini) | memory_limit، حجم آپلود، زمان اجرا |
| [`.liaraignore`](../.liaraignore) | کنترل آپلود (تا `public/build` آپلود شود، سکرت‌ها مستثنی) |
| [`.env.liara.example`](../.env.liara.example) | مرجع متغیرهای محیطی |

---

## پیش‌نیاز

```bash
npm i -g @liara/cli
liara login
```

مقادیر آماده:
```bash
php -r "echo bin2hex(random_bytes(32)).\"\n\";"   # APP_SECRET
openssl rand -hex 32                               # JWT_PASSPHRASE
ddev exec php docker/gen-cors-env.php              # ALLOWED_FRONTEND_HOSTS + CORS_ALLOW_ORIGIN
```

---

## گام ۱ — build محلی asset‌ها (حیاتی)

پلتفرم PHP لیارا **`yarn` اجرا نمی‌کند** و asset‌های React را نمی‌سازد. قبل هر دیپلوی محلی build کن (خروجی در `public/build`؛ `.liaraignore` آن را آپلود می‌کند):

```bash
ddev exec yarn install --frozen-lockfile
ddev exec yarn build
```

> اگر این مرحله را رد کنی، پنل ادمین `/admin` لود نمی‌شود.

---

## گام ۲ — ساخت دیتابیس و Redis

کنسول لیارا:
1. **MariaDB 11.8** بساز (هماهنگ با `serverVersion=mariadb-11.8.0`).
2. **Redis** بساز.
3. روی هر دو **شبکهٔ خصوصی** فعال؛ هاست خصوصی/کاربر/رمز را یادداشت کن.

---

## گام ۳ — ساخت برنامهٔ PHP

1. New App → نوع **PHP** → نسخهٔ **8.2** (پروژه `php: >=8.2` می‌خواهد) → شناسه `clinicpro-api`.
2. آن را به **همان شبکهٔ خصوصیِ** DB و Redis وصل کن.

---

## گام ۴ — ساخت دیسک‌های ماندگار

در صفحهٔ برنامه، بخش Disks، این سه دیسک را با همین نام‌ها بساز (mount از `liara.json`):

| نام | mountTo | محتوا |
|---|---|---|
| `jwt` | `/var/www/config/jwt` | کلید JWT (نباید هر دیپلوی نو شود) |
| `uploads` | `/var/www/public/uploads` | فایل‌های عمومی |
| `var-uploads` | `/var/www/var/uploads` | فایل‌های خصوصی |

> ⚠️ ریشهٔ اپ فرض شده `/var/www`. اگر در لاگ مسیر دیگری دیدی، `mountTo` در `liara.json` را اصلاح کن.

---

## گام ۵ — متغیرهای محیطی

از روی [`.env.liara.example`](../.env.liara.example) ست کن (تب Environment یا CLI). یک‌بار روی app؛ workerها همان را می‌گیرند.

```bash
liara env set APP_ENV=prod APP_DEBUG=0 --app clinicpro-api
liara env set APP_SECRET=<...> JWT_PASSPHRASE=<...> --app clinicpro-api
liara env set DATABASE_URL="mysql://<user>:<pass>@<db-private-host>:3306/<db>?serverVersion=mariadb-11.8.0&charset=utf8mb4" --app clinicpro-api
liara env set REDIS_URL="redis://:<pass>@<redis-private-host>:6379" --app clinicpro-api
liara env set MESSENGER_TRANSPORT_DSN="redis://:<pass>@<redis-private-host>:6379/messages" --app clinicpro-api
liara env set JWT_SECRET_KEY='%kernel.project_dir%/config/jwt/private.pem' JWT_PUBLIC_KEY='%kernel.project_dir%/config/jwt/public.pem' --app clinicpro-api
liara env set APP_BASE_URL=https://<domain> DEFAULT_URI=https://<domain> --app clinicpro-api
liara env set TRUSTED_PROXIES="10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1" --app clinicpro-api
liara env set ALLOWED_FRONTEND_HOSTS="<output>" CORS_ALLOW_ORIGIN="<output>" --app clinicpro-api
liara env set API_IR_BASE_URL=https://s.api.ir API_IR_TOKEN=<token> --app clinicpro-api
liara env set REFRESH_TOKEN_TTL=2592000 OTP_TTL=1200 MAX_FILE_SIZE_BYTES=5242880 UPLOAD_DIR=var/uploads --app clinicpro-api
```

نکته‌ها:
- `RUN_INIT` را ست **نکن** — init یک‌بار در `liara_pre_start.sh` اجرا می‌شود.
- `APP_ENV=prod` موقع build هم لازم است (composer اسکریپت `cache:clear` را اجرا می‌کند).
- کلیدهای SMS و درگاه پرداخت از **دیتابیس** خوانده می‌شوند، نه env.

---

## گام ۶ — دیپلوی

از ریشهٔ `clinicpro/`:
```bash
liara deploy
```

روند خودکار:
1. `liara_pre_build.sh` → `.env` مینیمال prod (اگر نبود).
2. `composer install` (لیارا).
3. `liara_pre_start.sh` → انتظار DB → تولید JWT (روی دیسک) → warmup → migration.
4. Apache (docroot=`public`) + `supervisor.conf` (هر دو worker) بالا می‌آیند.

---

## گام ۷ — اتصال دامنه و تأیید

1. بخش Domains: دامنهٔ API را وصل کن، TLS بگیر.
2. سلامت:
   ```bash
   curl -i https://<domain>/health      # باید 200
   ```
3. workerها:
   ```bash
   # در کنسول/CLI برنامه:
   supervisorctl status                 # worker-async و worker-scheduler = RUNNING
   ```
4. ورود `/admin` و تست یک endpoint (تأیید DB/Redis).

---

## دیپلوی‌های بعدی

```bash
ddev exec yarn build      # اگر assets عوض شد
liara deploy
```

migrationها خودکار در `liara_pre_start.sh` اجرا می‌شوند. دیسک‌ها و env حفظ می‌شوند.

---

## نگاشت compose → لیارا (PHP platform)

در `docker-compose.yml` هر worker یک کانتینر جدا بود؛ اینجا هر دو در همان کانتینر با `supervisor.conf`:

| compose | لیارا |
|---|---|
| سرویس `app` (php-fpm+nginx) | خود پلتفرم PHP (Apache+PHP-FPM)، docroot=`public` |
| `worker-async` (کانتینر جدا) | `[program:worker-async]` در `supervisor.conf` |
| `worker-scheduler` (کانتینر جدا) | `[program:worker-scheduler]` در `supervisor.conf` |
| `environment: *app-env` + `RUN_INIT` | env روی app؛ init در `liara_pre_start.sh` |
| `volumes` | دیسک‌های `liara.json` |
| `networks: [coolify]` | شبکهٔ خصوصی لیارا |
| `restart`/`healthcheck` | `autorestart=true` |
| `stop_grace_period: 30s` | `stopsignal=TERM` + `stopwaitsecs=30` |

---

## رفع اشکال

| نشانه | علت | راه‌حل |
|---|---|---|
| پنل `/admin` سفید/۴۰۴ asset | `public/build` آپلود نشده | `ddev exec yarn build` قبل deploy؛ `.liaraignore` build را مستثنی نکند |
| کل سایت ۴۰۳/۴۰۴ | documentRoot روی `public` نیست یا `.htaccess` نیست | `documentRoot: public` در liara.json + `public/.htaccess` |
| `Database not reachable after 60s` | شبکهٔ خصوصی/`DATABASE_URL` غلط | DB و app یک شبکه؛ هاست خصوصی را چک کن |
| توکن‌ها بعد هر دیپلوی باطل | دیسک `jwt` mount نشده | دیسک `jwt` → `/var/www/config/jwt` |
| worker بالا نمی‌آید / messenger خطای redis | افزونهٔ `redis` روی پلتفرم نیست | `php -m \| grep redis`؛ نبود → `MESSENGER_TRANSPORT_DSN=doctrine://default` + کش فایل‌سیستم |
| build به‌خاطر composer scripts شکست | `cache:clear` موقع نصب | مطمئن شو `APP_ENV=prod` ست است؛ در صورت لزوم نصب را `--no-scripts` کن و همه‌چیز را به `liara_pre_start.sh` بسپار |
| خطای CORS از فرانت | `CORS_ALLOW_ORIGIN` قدیمی | `docker/gen-cors-env.php` دوباره؛ env به‌روز |

---

## ریسک‌های شناخته‌شده

- **ext-redis:** اگر پلتفرم PHP لیارا phpredis نداشته باشد، Redis (cache + messenger) کار نمی‌کند → fallback به Doctrine transport و کش فایل‌سیستم. قبل اتکا verify کن.
- **مسیر دیسک:** ریشهٔ `/var/www` فرض است؛ با لاگ واقعی تطبیق بده.
- **انتخاب مسیر:** یا Docker یا PHP platform — هر دو `liara.json` را همزمان نگه ندار.
