# راهنمای استقرار production

## الگوی پیشنهادی

`Nginx → web` و در شبکهٔ داخلی `PostgreSQL + Redis + worker + scheduler` اجرا می‌شوند. فقط Nginx port عمومی دارد. migrationها idempotent هستند و web هنگام startup آن‌ها را اجرا می‌کند؛ با این حال همیشه قبل از نسخهٔ جدید backup بگیرید.

## ۱. آماده‌سازی سرور

روی Linux نصب Docker Engine و Compose Plugin کافی است. روی Windows Server از Docker با Linux containers یا یک VM لینوکسی استفاده کنید. حداقل پیشنهادی برای بار داخلی کوچک: ۲ هسته، ۴ گیگابایت RAM و دیسک SSD با backup خارج از میزبان.

```bash
git clone <repository-url> mandegar-delivery
cd mandegar-delivery
cp .env.example .env
```

## ۲. تنظیم secrets

فایل `.env` production را حداقل با مقادیر زیر تکمیل کنید. رمز PostgreSQL و Redis را URL-safe (حروف و عدد، طول زیاد) انتخاب کنید تا در connection URL نیاز به encode نداشته باشد.

```dotenv
APP_URL=https://delivery.example.com
APP_KEY=<random-at-least-48-chars>
SESSION_SECRET=<different-random-at-least-48-chars>
POSTGRES_DB=mandegar
POSTGRES_USER=mandegar
POSTGRES_PASSWORD=<long-url-safe-secret>
REDIS_PASSWORD=<different-long-url-safe-secret>
HTTP_PORT=8080
APP_VERSION=1.0.0
LOG_LEVEL=info
VAPID_SUBJECT=mailto:it@example.com
VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=
```

تولید کلید عمومی:

```bash
openssl rand -base64 48
```

برای Web Push، یک‌بار `npx web-push generate-vapid-keys` اجرا و خروجی را در secrets manager قرار دهید. فایل `.env` باید فقط برای کاربر استقرار قابل خواندن باشد (`chmod 600 .env`).

## ۳. build و راه‌اندازی

```bash
docker compose config
docker compose build --pull
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:8080/health/ready
```

سپس مدیر اولیه را ایجاد کنید:

```bash
docker compose exec web node dist/cli/bootstrap-admin.js admin "مدیر سامانه"
```

رمز موقت را همان لحظه در password manager امن ذخیره و در اولین ورود عوض کنید. `SEED_DEMO_USERS` در production همیشه false است.

## ۴. HTTPS با Nginx

در معماری سازمانی بهتر است load balancer/Nginx میزبان TLS را terminate و به port 8080 فوروارد کند. الزام‌ها:

- `X-Forwarded-Proto https` و `X-Forwarded-For` ارسال شوند.
- WebSocket مسیر `/ws` با headerهای Upgrade/Connection عبور کند.
- حداکثر body با `MAX_UPLOAD_MB` هماهنگ باشد.
- HTTP به HTTPS redirect شود و HSTS پس از اطمینان از گواهی فعال شود.

نمونهٔ کامل در `deployment/nginx/mandegar-https.conf.example` است. برای Let's Encrypt می‌توان روی میزبان گواهی گرفت:

```bash
sudo certbot certonly --webroot -w /var/www/certbot -d delivery.example.com
```

سپس مسیر گواهی را read-only به container Nginx mount و config نمونه را فعال کنید. قبل از reload:

```bash
nginx -t
docker compose restart nginx
```

## ۵. به‌روزرسانی بدون از دست‌رفتن داده

```bash
docker compose exec -T postgres pg_dump -U mandegar -d mandegar -Fc > backup-before-upgrade.dump
docker compose build --pull
docker compose up -d --remove-orphans
docker compose ps
curl -fsS https://delivery.example.com/health/ready
```

برای کاهش وقفه، ابتدا image را build کنید و سپس فقط web/worker/scheduler را recreate کنید. migration شکستن‌پذیر را در دو release سازگار اجرا کنید (expand سپس contract).

## ۶. rollback

1. `APP_VERSION` را به tag image قبلی برگردانید.
2. اگر migration فقط افزایشی و backward-compatible است، `docker compose up -d` کافی است.
3. اگر schema ناسازگار شده، سامانه را متوقف و dump پیش از ارتقا را روی یک database تازه restore کنید؛ روی پایگاه فعال restore درجا نکنید.
4. health، ورود، فهرست فاکتورها و یک گزارش نمونه را بررسی کنید.

## ۷. پایش

- `/health/live`: زنده‌بودن process.
- `/health/ready`: آماده‌بودن پایگاه.
- `docker compose logs -f --since=15m web worker scheduler nginx`.
- هشدار روی restart loop، خطای migration، jobهای `failed`، فضای دیسک PostgreSQL و نرخ 5xx.
- logها JSON هستند و فیلدهای cookie، authorization و password redacted می‌شوند.

## ۸. مقیاس‌پذیری

با Redis فعال، چند web instance می‌توانند session و pub/sub را به اشتراک بگذارند. Nginx بین آن‌ها load balance می‌کند و sticky session لازم نیست. چند worker مجازند چون job با `FOR UPDATE SKIP LOCKED` claim می‌شود. scheduler را فقط یک replica اجرا کنید.

## ۹. سخت‌سازی

- PostgreSQL و Redis را public نکنید؛ شبکهٔ `backend` در Compose internal است.
- firewall فقط 80/443 و SSH محدود را باز کند.
- imageها را با digest pin و به‌طور دوره‌ای اسکن کنید.
- secrets را در Git، image، log یا ticket قرار ندهید.
- backup رمزنگاری‌شده و آزمون restore فصلی داشته باشید.
- زمان میزبان را با NTP همگام نگه دارید؛ ذخیره‌سازی UTC و نمایش تهران است.
