Files
clinicpro/.claude/prompt/deploy-liara-php.md
T

13 KiB
Raw Blame History

دیپلوی ClinicPro (Symfony) روی لیارا با پلتفرم PHP (بدون داکر)

پروژه

clinicpro (Backend Symfony 7.4 + پنل ادمین React 19).

راهنما + تسک پیاده‌سازی برای دیپلوی روی پلتفرم PHP لیارا (buildpack بومی؛ لیارا خودش از سورس با composer install build می‌کند — بدون Dockerfile).

منابع: مستندات لیارا — paas/php/how-tos (set-envs، use-disk، set-logs، customize-php-ini، customize-htaccess، use-queues، set-http-security-headers، use-hooks، set-cron-job) و paas/laravel (quick-start، set-envs، set-cron-job، choose-version، manage-logs).


زمینه

تا الان دو مسیر دیپلوی برای این پروژه آماده شده:

  • داکر/Coolify: Dockerfile + docker-compose.yml
  • داکر/لیارا: liara.json (platform docker) + liara-compose.yaml

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

تفاوت‌های کلیدی پلتفرم PHP که معماری را تعیین می‌کنند (از مستندات):

  • Hookها فایل‌های شل‌اند، نه JSON: liara_pre_build.sh (قبل build، بدون دسترسی به env، مناسب apt) و liara_pre_start.sh (قبل start، با env، مناسب migration).
  • Worker با supervisor.conf: فایل supervisor.conf در ریشه؛ هر [program] یک دستور دلخواه (php bin/console messenger:consume ...) را زنده نگه می‌دارد. $ROOT = ریشهٔ اپ، user=www-data.
  • php.ini با liara_php.ini در ریشه.
  • سرو با Apache + .htaccess؛ documentRoot باید public/ شود.
  • دیسک‌ها در liara.json با مسیر absolute.
  • نسخهٔ PHP: 7.2 تا 8.4 (پیش‌فرض 7.4) — پروژه php: >=8.2 می‌خواهد، پس باید 8.2+ انتخاب شود.

مشکل / هدف

اجرای کامل Symfony روی پلتفرم PHP لیارا، شامل:

  1. سرو front-controller سیمفونی از public/ روی Apache.
  2. اجرای migration و تولید کلید JWT در زمان استقرار.
  3. اجرای دو مصرف‌کنندهٔ Messenger (async و scheduler_default) به‌صورت پایدار.
  4. آپلودِ asset‌های build‌شدهٔ React (که composer install آن‌ها را نمی‌سازد).
  5. اتصال به MariaDB و Redis مدیریت‌شدهٔ لیارا.

فایل‌های مرتبط

فایل نقش وضعیت
liara.json پیکربندی دیپلوی بازنویسی برای platform php (فعلاً platform docker است)
public/.htaccess rewrite سیمفونی برای Apache وجود ندارد — ساخته شود (apache-pack نصب نیست)
liara_pre_start.sh hook قبل start (migration/JWT) جدید
supervisor.conf اجرای دو worker جدید
liara_php.ini تنظیم php.ini جدید
.liaraignore کنترل فایل‌های آپلودی جدید (تا public/build آپلود شود)
composer.json اسکریپت‌های نصب بدون تغییر (با احتیاط؛ پایین)

⚠️ تداخل liara.json: الان liara.json برای platform docker است. پلتفرم PHP به محتوای متفاوتی نیاز دارد. فقط یک مسیر را همزمان نگه دار. اگر PHP را انتخاب کردی، محتوای docker را با نسخهٔ PHP زیر جایگزین کن (یا برنچ جدا).


وضعیت فعلی (کد واقعی)

composer.json هنگام نصب این اسکریپت‌ها را اجرا می‌کند (روی build لیارا هم اجرا می‌شوند):

"auto-scripts": {
  "cache:clear": "symfony-cmd",
  "assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": ["@auto-scripts"]

.gitignore این‌ها را نادیده می‌گیرد (پس به‌صورت پیش‌فرض آپلود نمی‌شوند):

/public/build/      # ← خروجی yarn build؛ باید آپلود شود
/config/jwt/*.pem   # ← روی دیسک ساخته می‌شود
/var/
.env

public/.htaccess وجود ندارد؛ extensionهای موردنیاز Symfony: pdo_mysql, intl, opcache, و برای Messenger روی Redis: redis (phpredis).


وظایف

۱. ساخت liara.json برای پلتفرم PHP

محتوای فعلی (platform docker) را با این جایگزین کن:

{
  "app": "clinicpro-api",
  "platform": "php",
  "port": 80,
  "php": {
    "version": "8.2"
  },
  "documentRoot": "public",
  "disks": [
    { "name": "jwt", "mountTo": "/var/www/config/jwt" },
    { "name": "uploads", "mountTo": "/var/www/public/uploads" },
    { "name": "var-uploads", "mountTo": "/var/www/var/uploads" }
  ]
}

نکات:

  • documentRoot: "public" تا Apache front-controller سیمفونی را سرو کند.
  • مسیر mount دیسک‌ها absolute است؛ ریشهٔ اپ روی پلتفرم PHP معمولاً /var/www است — اگر در کنسول/لاگ مسیر دیگری دیدی، اصلاح کن.
  • کلید php.version و documentRoot را اگر کنسول نپذیرفت، از تنظیمات کنسول (Platform Settings) ست کن — مستند نسخه‌گزینی را از طریق کنسول هم ممکن می‌داند.
  • سه دیسک jwt / uploads / var-uploads را پیش از دیپلوی در کنسول بساز.

۲. ساخت public/.htaccess (rewrite سیمفونی)

چون symfony/apache-pack نصب نیست، یا نصبش کن:

ddev exec composer require symfony/apache-pack

(این به‌صورت تعاملی public/.htaccess استاندارد سیمفونی را می‌سازد) — یا فایل را دستی بساز:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_URI}::$0 ^(/.+)/(.*)::\2$
    RewriteRule .* - [E=BASE:%1]
    RewriteCond %{HTTP:Authorization} .+
    RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]
    RewriteCond %{ENV:REDIRECT_STATUS} =""
    RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^ - [L]
    RewriteRule ^ %{ENV:BASE}/index.php [L]
</IfModule>
<IfModule !mod_rewrite.c>
    <IfModule mod_alias.c>
        RedirectMatch 307 ^/$ /index.php/
    </IfModule>
</IfModule>

۳. ساخت supervisor.conf (دو worker مسنجر)

روی پلتفرم PHP، خود لیارا Apache/PHP-FPM را اجرا می‌کند؛ supervisor.conf فقط workerها را اضافه می‌کند (نه وب). در ریشه بساز:

[program:worker-async]
process_name=%(program_name)s_%(process_num)02d
command=cd $ROOT && php bin/console messenger:consume async --time-limit=3600 --memory-limit=128M -v
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
numprocs=1
user=www-data
redirect_stderr=true
stdout_logfile=/tmp/worker-async.log

[program:worker-scheduler]
process_name=%(program_name)s_%(process_num)02d
command=cd $ROOT && php bin/console messenger:consume scheduler_default --time-limit=3600 -v
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
numprocs=1
user=www-data
redirect_stderr=true
stdout_logfile=/tmp/worker-scheduler.log

جایگزینِ cron: اگر نخواهی scheduler به‌صورت worker بماند، می‌توانی همان کار را با Cron Job کنسول (* * * * * → دستوری که یک پیام scheduler را مصرف کند) انجام دهی. ولی worker async (SMS) حتماً باید در supervisor.conf بماند.

۴. ساخت liara_pre_start.sh (migration + JWT + cache)

در ریشه، با env در دسترس:

#!/bin/sh
set -e

echo "pre-start: waiting for database..."
i=0
until php bin/console doctrine:query:sql "SELECT 1" >/dev/null 2>&1; do
    i=$((i + 1))
    [ "$i" -ge 30 ] && { echo "DB not reachable after 60s" >&2; exit 1; }
    sleep 2
done

# کلید JWT روی دیسک ماندگار jwt
php bin/console lexik:jwt:generate-keypair --skip-if-exists --no-interaction

php bin/console cache:clear --no-warmup
php bin/console cache:warmup
php bin/console doctrine:migrations:migrate --all-or-nothing --no-interaction

فایل را اجرایی کن: chmod +x liara_pre_start.sh.

۵. ساخت liara_php.ini

برای پشتیبانی از آپلود (سقف اپ ۵MB ولی هدر/چندبخشی بزرگ‌تر) و زمان اجرا:

memory_limit = 256M
upload_max_filesize = 16M
post_max_size = 24M
max_execution_time = 120
file_uploads = On

۶. ساخت .liaraignore تا asset‌های build آپلود شوند

.gitignore پوشهٔ /public/build/ را نادیده می‌گیرد و لیارا به‌صورت پیش‌فرض از gitignore پیروی می‌کند → asset‌ها آپلود نمی‌شوند. با ساخت .liaraignore کنترل را به‌دست بگیر (فقط واقعاً غیرلازم‌ها را کنار بگذار، public/build را نگه دار):

.git
.ddev
.claude
.github
.vscode
node_modules
tests
var/cache
var/log
docs
graphify-out
*.sql
*.sql.gz
.DS_Store

پیش از هر دیپلوی، asset‌ها را محلی build کن (لیارا yarn build نمی‌زند):

ddev exec yarn install --frozen-lockfile
ddev exec yarn build        # خروجی در public/build

۷. دیتابیس و Redis مدیریت‌شده + متغیرهای محیطی

مثل مسیر داکر:

  1. در کنسول، MariaDB 11.8 و Redis بساز، شبکهٔ خصوصی فعال، برنامه را به همان شبکه وصل کن.
  2. envها را با liara env set ... --app clinicpro-api یا تب Environment ست کن (مرجع کامل: .env.liara.example). حداقل:
    • APP_ENV=prod, APP_DEBUG=0
    • APP_SECRET, JWT_PASSPHRASE (ثابت)
    • DATABASE_URL (هاست خصوصی MariaDB، serverVersion=mariadb-11.8.0)
    • REDIS_URL, MESSENGER_TRANSPORT_DSN (هاست خصوصی Redis)
    • JWT_SECRET_KEY/JWT_PUBLIC_KEY (مسیر config/jwt/*.pem)
    • APP_BASE_URL, DEFAULT_URI, TRUSTED_PROXIES
    • ALLOWED_FRONTEND_HOSTS, CORS_ALLOW_ORIGIN (خروجی php docker/gen-cors-env.php)
    • API_IR_BASE_URL, API_IR_TOKEN
  3. مهم: APP_ENV=prod باید موقع build هم موجود باشد، چون composer install اسکریپت cache:clear را اجرا می‌کند.

۸. استقرار و تأیید

liara deploy        # از ریشهٔ clinicpro، با liara.json platform php

سپس:

  • GET https://<domain>/health → 200
  • لاگ: در کنسول/liara logs هر دو worker (worker-async, worker-scheduler) بالا باشند
  • ورود /admin و تست یک endpoint

نکات مهم

  • ext-redis ریسک اصلی است: اگر پلتفرم PHP لیارا افزونهٔ redis (phpredis) را نداشته باشد، REDIS_URL و MESSENGER_TRANSPORT_DSN: redis://... کار نمی‌کنند. اول در محیط لیارا چک کن (php -m | grep redis). اگر نبود:
    • برای Messenger به transport مبتنی بر Doctrine سوییچ کن (MESSENGER_TRANSPORT_DSN=doctrine://default) و جدول مسنجر را با migration بساز،
    • برای cache هم به adapter فایل‌سیستم/Doctrine برگرد.
  • اسکریپت‌های composer در build: cache:clear در prod بدون DB معمولاً سالم است؛ اگر build به خاطر اسکریپت‌ها شکست، می‌توان نصب را بدون اسکریپت کرد و همه‌چیز را به liara_pre_start.sh سپرد (هماهنگ با کاری که Dockerfile با --no-scripts می‌کند).
  • ماندگاری کلید JWT: دیسک jwt حتماً mount شود؛ وگرنه هر دیپلوی کلید نو می‌سازد و توکن‌ها باطل می‌شوند.
  • asset‌ها فراموش نشوند: اگر public/build آپلود نشود، پنل ادمین لود نمی‌شود — قبل دیپلوی yarn build و .liaraignore درست.
  • documentRoot: اگر روی public ست نشود، Apache فایل‌های ریشه را سرو می‌کند و اپ ۴۰۴/۴۰۳ می‌دهد.
  • هماهنگی نسخهٔ DB: serverVersion در DATABASE_URL با نسخهٔ MariaDB مدیریت‌شده یکی باشد (11.8).
  • این تغییر فقط زیرساخت دیپلوی است و هیچ route/endpoint را عوض نمی‌کند → نیازی به‌روزرسانی docs/api/* نیست.
  • یک مسیر را انتخاب کن: Docker (liara.json فعلی + liara-compose.yaml) یا PHP platform (این پرامپت). همزمان هر دو liara.json نگه‌داشتنی نیست.