TenantInsurance reads ran through the tenant filter, which pins every query to the *requesting* user's environment. A clinic owner managing a doctor's contracts therefore read an empty set, recomputed version 1, and hit `uniq_tenant_insurance_version` on insert. The reads now bypass the filter — authorization is already established by resolveTargetEntity(), and the uuid-based paths re-assert ownership after loading. UserActiveContext::upsert() raced with itself: the panel fires several /oauth/userinfo requests at once, all saw no row, all inserted, and the losers died on a duplicate PRIMARY (closing the EntityManager with them). Replaced with INSERT ... ON DUPLICATE KEY UPDATE. A service that carries a treatment protocol but no catalog category is bad catalog data, not a system failure; it was logged at error level on every confirm and buried the real errors. Now a warning carrying the service id. Kavenegar's HTTP 431 says only "malformed request". The provider's own message and the token slot names are now logged so the template can actually be fixed in the panel; token values stay out of the log. Redis DSNs gained timeout/retry_interval/tcp_keepalive so a brief connection loss reconnects quietly instead of logging a warning each time. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
71 lines
2.9 KiB
Bash
71 lines
2.9 KiB
Bash
###> symfony/framework-bundle ###
|
|
APP_ENV=prod
|
|
# IMPORTANT: generate a strong random secret for production:
|
|
# php -r "echo bin2hex(random_bytes(32));"
|
|
APP_SECRET=CHANGE_ME_STRONG_RANDOM_32_CHARS
|
|
APP_SHARE_DIR=var/share
|
|
###< symfony/framework-bundle ###
|
|
|
|
###> symfony/routing ###
|
|
DEFAULT_URI=https://your-domain.com
|
|
###< symfony/routing ###
|
|
|
|
###> doctrine/doctrine-bundle ###
|
|
DATABASE_URL="mysql://user:CHANGE_ME@db:3306/clinic_pro?serverVersion=8.0&charset=utf8mb4"
|
|
###< doctrine/doctrine-bundle ###
|
|
|
|
###> lexik/jwt-authentication-bundle ###
|
|
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
|
|
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
|
|
# Generate with: openssl rand -hex 32
|
|
JWT_PASSPHRASE=CHANGE_ME_STRONG_PASSPHRASE
|
|
###< lexik/jwt-authentication-bundle ###
|
|
|
|
###> nelmio/cors-bundle ###
|
|
# رجکسِ CORS در PHP از روی ALLOWED_FRONTEND_HOSTS ساخته میشود (CorsRegexEnvProcessor).
|
|
# CORS_ALLOW_ORIGIN دیگر استفاده نمیشود — ست نکن.
|
|
###< nelmio/cors-bundle ###
|
|
|
|
###> symfony/messenger ###
|
|
MESSENGER_TRANSPORT_DSN=redis://redis:6379/messages
|
|
###< symfony/messenger ###
|
|
|
|
###> Redis ###
|
|
# retry_interval/tcp_keepalive: قطع کوتاه اتصال به redis بیسروصدا دوباره برقرار میشود
|
|
# و «Connection lost» بهصورت warning در app_log نمینشیند.
|
|
REDIS_URL=redis://redis:6379?timeout=5&read_timeout=5&retry_interval=100&tcp_keepalive=60
|
|
###< Redis ###
|
|
|
|
###> Auth ###
|
|
REFRESH_TOKEN_TTL=2592000
|
|
OTP_TTL=1200
|
|
###< Auth ###
|
|
|
|
###> SMS ###
|
|
# کلید API کاوهنگار فقط از همین env خوانده میشود (نه DB).
|
|
KAVENEGAR_API_KEY=
|
|
###< SMS ###
|
|
|
|
###> api.ir Identity Inquiry (Shahkar + IbanMatch) ###
|
|
# استعلام هویت نماینده: تطبیق کد ملی با موبایل (شاهکار) و تطبیق شبا با کد ملی.
|
|
# توکن خالی = سرویس fail-closed (استعلام انجام نمیشود و تأیید رد میشود).
|
|
API_IR_BASE_URL=https://s.api.ir
|
|
API_IR_TOKEN=CHANGE_ME
|
|
###< api.ir Identity Inquiry ###
|
|
|
|
###> File Upload ###
|
|
MAX_FILE_SIZE_BYTES=5242880
|
|
UPLOAD_DIR=var/uploads
|
|
###< File Upload ###
|
|
|
|
###> Payment ###
|
|
# میزبانهای مجاز برای redirect بازگشت پرداخت (کاما-جدا): پنل + دامنههای عمومی نوبتدهی.
|
|
ALLOWED_FRONTEND_HOSTS=clinic-pro.ir,yasuj-nobat.ir,yazd-nobat.ir
|
|
# باید دقیقاً دامنهٔ ثبتشده نزد ملت/شاپرک باشد (callBackUrl از این ساخته میشود؛ IP مجاز نیست — کد پاسخ 62).
|
|
APP_BASE_URL=https://clinic-pro.ir
|
|
# کلیدهای درگاه (mellat/sep) از پنل «تنظیمات سایت» (DB) خوانده میشوند؛ env فقط fallback اختیاری است.
|
|
###< Payment ###
|
|
|
|
# لاگین سرویسی کرالر: مقدار غیرخالی، هدر X-Service-Token را برای دورزدن کپچای لاگین فعال میکند (فقط کپچا)
|
|
CRAWLER_SERVICE_TOKEN=
|