# ADR-R3: جایگزینی RabbitMQ/Workers با Queue دیتابیسی + Cron، و S3/MinIO با storage محلی

- **تاریخ:** 2026-09-07
- **وضعیت:** پیشنهادی — نیازمند تأیید مالک پروژه (حسن)
- **ارتباط:** جایگزین بخشی از ADR-001 و ADR-007 (Outbox)

## زمینه (Context)
RabbitMQ و MinIO روی هاست ابری سون‌هاست موجود نیستند و SSH هم در دسترس نیست (تأیید پشتیبانی).
کد مرجع: Outbox-publisher هر ۲ ثانیه رویدادها را به RabbitMQ می‌فرستد؛ اپ `workers` دو مصرف‌کننده
(SMS/Notification) دارد؛ فایل‌های پزشکی در MinIO با presigned URL.

## گزینه‌های بررسی‌شده (Options)
1. **سرویس S3 ایرانی خارج از هاست (آروان و…)** — رد شد: تصمیم مالک «همه‌چیز روی همین سرور».
2. **Webhooks بدون صف** — از دست رفتن رویداد در خطا؛ نقض Outbox (ADR-007).
3. **Laravel Queue درایور database + schedule:run با Cron cPanel + storage محلی رمزنگاری‌شده**

## تصمیم (Decision)
گزینه ۳:

**صف و رویدادها:**
- Outbox (ADR-007) حفظ می‌شود: جدول `core_outbox_events` — نوشتن رویداد در همان تراکنش دامنه.
- ناشر: scheduled job (هر دقیقه) رویدادهای منتشرنشده را می‌خواند و consumerهای مربوطه را
  **in-process** فراخوانی می‌کند (بدون AMQP)؛ تلاش مجدد با backoff در همان جدول.
- صف‌های Laravel (درایور `database`) برای کارهای سنگین (ارسال SMS، نوتیفیکیشن، تسویه زمان‌دار Escrow)
  و worker: `php artisan queue:work --stop-when-empty` از طریق Cron هر دقیقه (حداکثر تأخیر ۶۰s).
- **قاعده:** پرداخت/Escrow هرگز به صف وابسته نیست — هم‌زمان (sync) در تراکنش انجام می‌شود؛
  صف فقط برای SMS/Notification (همان دامنه RabbitMQ در نسخه مرجع).

**فایل‌ها:**
- Storage محلی: `storage/app/private/` (خارج public_html، دسترسی وب غیرممکن).
- پرونده‌های پزشکی (PHI): رمزنگاری AES-256-GCM با sodium در سکون قبل از write.
- دانلود فقط از طریق endpoint لاراول با اعتبارسنجی grant + signed URL کوتاه‌عمر (مولد خودم، چون
  presigned S3 خارج از هاست نیست).

## پیامدها (Consequences)
- **مثبت:** صفر سرویس خارجی؛ Outbox و تضمین «حداقل یک‌بار» حفظ می‌شود؛ PHI هرگز raw روی دیسک نیست.
- **منفی:** تأخیر رویدادها/پیامک تا ~۶۰ ثانیه؛ throughput صف محدود به Cron (برای فاز ۱ کافی).
- **استقرار بدون SSH:** دستورات artisan (migrate، queue:work) از طریق Cron cPanel اجرا می‌شوند —
  یک اسکریپت `artisan-via-cron.sh` با قفل `GET_LOCK` ضد اجرای هم‌زمان.

## ارجاعات
- نسخه مرجع: `iraniraqgate/apps/workers/src/` (consumers)، `shared/events/outbox-publisher.service.ts`
- ADR-007 (Outbox)، فصل ۳.۳ و ۱۱.۴
