# راهنمای دیپلوی ClinicPro روی لیارا (Docker)

این راهنما قدم‌به‌قدم نشان می‌دهد چطور بک‌اند Symfony را روی **لیارا** با پلتفرم **Docker** بالا بیاوری.

> چرا متفاوت با Coolify؟ لیارا **از docker-compose پشتیبانی نمی‌کند**. استک ۳-سرویسی compose (وب + ۲ worker) به یک **برنامهٔ داکر تکی** تبدیل شده که هر سه پروسه را با Supervisor اجرا می‌کند. MariaDB و Redis سرویس‌های مدیریت‌شدهٔ جدا روی شبکهٔ خصوصی‌اند.

---

## نمای کلی معماری

```
┌─────────────────────────── Liara private network ───────────────────────────┐
│                                                                              │
│   ┌────────────────────────────┐      ┌───────────────┐   ┌──────────────┐   │
│   │  clinicpro-api (Docker)    │      │  MariaDB 11.8 │   │    Redis     │   │
│   │  Supervisor:               │◄────►│  (managed)    │   │  (managed)   │   │
│   │   • php-fpm + nginx :8080  │      └───────────────┘   └──────────────┘   │
│   │   • worker-async           │                                             │
│   │   • worker-scheduler       │   disks: jwt / uploads / var-uploads        │
│   └─────────────┬──────────────┘                                             │
└─────────────────┼────────────────────────────────────────────────────────────┘
                  │ :8080 (تنها پورت HTTP بیرونی)
                  ▼
            https://<your-domain>
```

فایل‌های کلیدی در ریپو:
- [`liara.json`](../liara.json) — پیکربندی دیپلوی (platform، port، دیسک‌ها، healthcheck)
- [`Dockerfile`](../Dockerfile) — image چندمرحله‌ای (بدون تغییر برای لیارا)
- [`docker/supervisord.conf`](../docker/supervisord.conf) — اجرای php-fpm + nginx + دو worker
- [`docker/entrypoint.sh`](../docker/entrypoint.sh) — wait-for-DB، تولید JWT، migration
- [`.env.liara.example`](../.env.liara.example) — مرجع متغیرهای محیطی

---

## پیش‌نیازها

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

مقادیری که از قبل آماده کن:

```bash
# APP_SECRET
php -r "echo bin2hex(random_bytes(32)).\"\n\";"

# JWT_PASSPHRASE
openssl rand -hex 32

# دامنه‌های فرانت (ALLOWED_FRONTEND_HOSTS + CORS_ALLOW_ORIGIN)
ddev exec php docker/gen-cors-env.php
```

---

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

در [کنسول لیارا](https://console.liara.ir):

1. **MariaDB 11.8** بساز. (نسخه باید با `serverVersion=mariadb-11.8.0` در `DATABASE_URL` یکی باشد.)
2. **Redis** بساز.
3. روی هر دو **شبکهٔ خصوصی** را فعال کن.
4. **هاست خصوصی** و کاربر/رمز هرکدام را از صفحهٔ سرویس یادداشت کن (مثلاً `clinicpro-db`، `clinicpro-redis`).

---

## گام ۲ — ساخت برنامهٔ داکر

1. در کنسول یک **App** از نوع **Docker** بساز با شناسهٔ `clinicpro-api` (همان `app` در `liara.json`).
2. آن را به **همان شبکهٔ خصوصیِ** DB و Redis متصل کن.

---

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

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

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

> ⚠️ بدون دیسک `jwt`، هر دیپلوی کلید جدید می‌سازد و **همهٔ توکن‌های صادرشده باطل** می‌شوند.

---

## گام ۴ — ست‌کردن متغیرهای محیطی

از روی [`.env.liara.example`](../.env.liara.example) مقادیر را در تب **Environment** یا با CLI ست کن:

```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://<redis-private-host>:6379" --app clinicpro-api
liara env set MESSENGER_TRANSPORT_DSN="redis://<redis-private-host>:6379/messages" --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
```

نکته‌ها:
- `RUN_INIT` را ست **نکن** — `entrypoint.sh` پیش‌فرض `1` می‌گیرد و چون تک‌برنامه است، تولید JWT + migration یک‌بار اجرا می‌شود.
- کلیدهای SMS و درگاه پرداخت از **دیتابیس** خوانده می‌شوند، نه env.

---

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

از ریشهٔ `clinicpro/`:

```bash
liara deploy
```

`liara.json` تنظیمات platform/port/disks/healthcheck را می‌دهد، پس فلگ اضافه لازم نیست. در اولین بالا آمدن:

1. `entrypoint.sh` تا ~۶۰ ثانیه صبر می‌کند تا DB جواب دهد.
2. کلید JWT می‌سازد (روی دیسک `jwt`).
3. کش prod را warmup می‌کند.
4. `doctrine:migrations:migrate` را اجرا می‌کند.
5. Supervisor، nginx/php-fpm و هر دو worker را بالا می‌آورد.

---

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

1. در بخش **Domains** برنامه، دامنهٔ API را وصل کن و TLS بگیر.
2. تست سلامت:
   ```bash
   curl -i https://<domain>/health        # باید 200 بدهد
   ```
3. لاگ‌ها:
   ```bash
   liara logs --app clinicpro-api --follow
   ```
   باید php-fpm، nginx، `worker-async` و `worker-scheduler` هر چهار بالا باشند.
4. ورود به پنل ادمین `/admin` و تست یک endpoint برای تأیید اتصال DB/Redis.

---

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

```bash
git pull            # یا تغییرات محلی
liara deploy
```

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

---

## رفع اشکال

| نشانه | علت محتمل | راه‌حل |
|---|---|---|
| `Database not reachable after 60s` در لاگ | شبکهٔ خصوصی وصل نیست یا `DATABASE_URL` غلط | DB و app روی یک شبکهٔ خصوصی باشند؛ هاست خصوصی و رمز را چک کن |
| توکن‌ها بعد از هر دیپلوی باطل | دیسک `jwt` mount نشده | دیسک `jwt` روی `/app/config/jwt` بساز |
| `/health` غیر-۲۰۰ | DB/Redis در دسترس نیست یا migration نخورده | لاگ entrypoint را ببین |
| خطای CORS از فرانت | `CORS_ALLOW_ORIGIN`/`ALLOWED_FRONTEND_HOSTS` قدیمی | `docker/gen-cors-env.php` را دوباره بزن و env را به‌روزرسانی کن |
| آپلودها بعد از دیپلوی گم می‌شوند | دیسک uploads mount نشده | دیسک‌های `uploads` و `var-uploads` را بساز |

---

## گزینهٔ جایگزین — worker مجزا

اگر خواستی workerها ایزوله باشند (به‌جای Supervisor تک‌کانتینر)، همین ریپو را به‌عنوان برنامهٔ داکر دومی با `liara.json` متفاوت دیپلوی کن که `command` را به `php bin/console messenger:consume ...` override کند، `RUN_INIT=0` بدهد و **بدون** پورت/دامنه باشد. گران‌تر (دو برنامهٔ داکر) ولی ایزوله‌تر. برای اکثر موارد گزینهٔ پیش‌فرض (Supervisor) کافی است.
