Files
clinicpro/.env.example
T
hamedandClaude Opus 5 5986fad5a1 fix(logs): resolve the five real defects surfaced by app_log
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>
2026-08-18 08:31:15 +03:30

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=