Skip to content

Environment variables

There are ~337 environment variables across the four repos (backend 159, crms-middleware 124, frontend 51, pdf-service 3). This page is the map, grouped by concern — the committed .env.example files (blank values) + config/*.php are the exhaustive, always-current source. Names and purpose only; no values appear anywhere in these docs. 🔐 marks a secret to rotate on handover.

Core — app / DB / cache / queue / logging

Section titled “Core — app / DB / cache / queue / logging”

Standard Laravel config, shared by backend (BE) and crms-middleware (MW): APP_NAME/APP_ENV/ APP_DEBUG/APP_URL, APP_KEY 🔐, LOG_CHANNEL/LOG_LEVEL, DB_* (+ DB_PASSWORD 🔐, DB_ROOT_PASSWORD 🔐), REDIS_HOST/REDIS_PORT (+ REDIS_PASSWORD 🔐), the driver set (CACHE_DRIVER/QUEUE_CONNECTION/SESSION_DRIVER/SESSION_LIFETIME), MAIL_* (+ MAIL_PASSWORD 🔐), PUSHER_* (+ PUSHER_APP_SECRET 🔐), MinIO dev storage (+ MINIO_ROOT_PASSWORD 🔐), SANCTUM_STATEFUL_DOMAINS, TELESCOPE_ENABLED, and PROMETHEUS_METRICS_ENABLED + PROMETHEUS_SCRAPE_METRICS_TOKEN 🔐.

The largest group — the CRM integration model explains the shape.

  • Backend → middleware (BE): CRMS_MIDDLEWARE_{BASE_URL,AUTH_URL,API_URL,GRANT_TYPE,CLIENT_ID} + CRMS_MIDDLEWARE_CLIENT_SECRET 🔐 (Passport client_credentials).
  • Write auth → Logic Apps (MW): LINK_DEV_{AUTH_URL,GRANT_TYPE,RESOURCE,CLIENT_ID} + LINK_DEV_CLIENT_SECRET 🔐 (Azure AD v1.0 resource=).
  • Read auth → per-country OData (MW): {EGYPT,OMAN,MONTENEGRO}_CRM_{AUTH_URL,GRANT_TYPE,SCOPE,BASE_URL, CLIENT_ID} + each _CLIENT_SECRET 🔐 (v2.0 scope=). The client id/secret are identical across LINK_DEV_* and all three *_CRM_* — one Azure AD app (see the single-credential note).
  • Logic-App operation URLs (MW): one *_URL per operation, grouped: LEAD_* (3), SALE_CRM_* / UNIT_* (unit/sale, ~9), SALESMAN_CRM_API_* (~14), CRM_API_EOI_* (~9), SHOPPER_DETAILS_URL, CRM_BROKER_SELF_SIGNUP, UNIT_SERVICE_SUBMIT/UNIT_RESELL_ASSISTANCE. See the full list in crms-middleware/.env.example.
  • Mocks (dev): OMAN_CRM_BROKER_CRM_MOCK_ENABLED + _BASE_URL, CRM_LEAD_ELIGIBLE_CRM_MOCK_ENABLED.
  • CMS (Payload): CMS_{BASE_URL,AUTH_URL,API_URL,CLIENT_ID,GRANT_TYPE} + CMS_CLIENT_SECRET 🔐.
  • Backend — Paymob (per Egyptian destination): {ELGOUNA,MAKADI,OWEST}_PAYMOB_API_KEY 🔐 + _HMAC_SECRET 🔐 + {dest}_{USD,EGP}_PAYMOB_INTEGRATION_ID; PAYMOB_{AUTH,ORDER,PAYMENT_KEY}_URL.
  • Backend — Thawani (Oman): THAWANI_{API_URL,CREATE_SESSION_URL,SUCCESS_URL,CANCEL_URL,PUBLIC_KEY} + THAWANI_SECRET_KEY 🔐. (THAWANI_CREATE_SESSION_URL — the endpoint ThawaniService actually POSTs to — is read from config but absent from .env.example; see drift.)
  • Backend — WSPG (Montenegro): WSPG_{API_URL,SHOP_ID,SUCCESS_URL,CANCEL_URL,FAIL_URL} + WSPG_SECRET_KEY 🔐.
  • Frontend redirect targets: NX_PAYMOB_IFRAME_URL, NX_THAWANI_IFRAME_URL, NX_THAWANI_PUBLIC_KEY, NX_WSPAY_PAYMENT_URL.

Adding a gateway? See Add a payment gateway.

Var Repo Default Purpose
PDF_SERVICE_URL BE http://localhost:3001 Microservice base URL
PDF_SERVICE_TOKEN 🔐 BE Bearer sent to the PDF service
PDF_SERVICE_TIMEOUT BE 120 (s) HTTP client timeout
PDF_SERVICE_GENERATE_RATE_LIMIT_PER_MINUTE BE 5 Per-user generate throttle
SALES_OFFER_DISK / SALES_OFFER_EXPIRY_DAYS BE (config/filesystems.php) — / 14 Disk + expiry (⚠ not in .env.example — see drift)
API_TOKEN 🔐 pdf-service Bearer for POST /api/sales-offer
PORT / BODY_PAYLOAD_LIMIT pdf-service 3001 / 20mb Listen port / max body
  • Microsoft SSO (sales-man): AZURE_{CLIENT_ID,TENANT_ID,OBJECT_ID} + AZURE_CLIENT_SECRET 🔐 (the secret the azure config group reads, config/services.php:63). ⚠ .env.example ships AZURE_SECRET_ID instead — which the SSO group doesn’t consume — so AZURE_CLIENT_SECRET is a drift (see below).
  • Per-persona SPA URLs (payment/redirect targets): SHOPPER_FRONTEND_URL, BROKER_FRONTEND_URL, SALES_MAN_FRONTEND_URL, SHOPPER_ADMIN_FRONTEND_URL, BROKER_DASHBOARD_URL, FRONTEND_RESET_PASS_PATH, the Oman pre-reg document paths.
  • Mail services (OAuth): ORASCOM_MAIL_* + ORASCOM_MAIL_CLIENT_SECRET 🔐; ORASCOM_OMAN_PRE_REGISTRATION_MAIL_* + its _CLIENT_SECRET 🔐.

SENTRY_LARAVEL_DSN 🔐 + sample-rate/env; the OTEL_* set (backend-only tracing/metrics/logs); FIREBASE_CREDENTIALS 🔐 (push); GA4 (GOOGLE_ANALYTICS_* + _PRIVATE_KEY/_PRIVATE_KEY_ID 🔐); AWS_* (S3 media; AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY 🔐); Infobip SMS (INFOBIP_BASE_URL/ _SENDER_ID + INFOBIP_API_KEY 🔐, ALLOW_SEND_SMS); ALLOW_TEST_OTP + OTP_TEST_CODE 🔐 (the test-OTP bypass — must be off in prod); Currency-Layer (CURRENY_LAYER_API_URL + CURRENY_LAYER_API_KEY 🔐 — note the intentional CURRENY typo); ops recipient lists (EOI_FAILED_EMAILS, ADMIN_EMAIL, …); UNIT_BLOCK_DURATION/UPDATE_INFO_DURATION (default 1 day, the reservation window — see the CRM-owned TTL).

Frontend NX_* (inlined into the browser bundle)

Section titled “Frontend NX_* (inlined into the browser bundle)”

Per-app API endpoints (NX__<persona>_API_ENDPOINT + _ENDPOINT_PREFIX) and token-storage keys (NX_*_ACCESS_TOKEN_KEY — the auth model lists the defaults); refresh-token config; the payment redirect vars (above); per-app Sentry DSNs + Firebase web config (public by design); and a set of feature flags (NX_HIDE_*, NX__ENABLE_EOI, NX_ALLOW_MULTIPLE_RESERVATIONS, …). The two exceptions that must not be here: NX_CLIENT_SECRET and NX_CURRENY_LAYER_API_KEY (see the danger callout at the top).

Config-vs-.env.example drift (fill these in for a real environment)

Section titled “Config-vs-.env.example drift (fill these in for a real environment)”

Several vars are read from config/*.php but missing from the committed .env.example — an operator who just copies .env.example won’t set them:

  • Backend: SALES_OFFER_DISK, SALES_OFFER_EXPIRY_DAYS (config/filesystems.php:27-28).
  • Middleware: MICROSOFT_ADMIN_GUID, CRM_EXCHANGE_RATE_URL (config/services.php).
  • Frontend: the per-project Thawani keys NX_THAWANI_{AMAZI,RAYA,SIFAH_FARMS,SOLARIS,BEACHFRONT2}_PUBLIC_KEY (note the BEACHFRONT2) — consumed in code but only the generic NX_THAWANI_PUBLIC_KEY ships in .env.example.
  • Backend: THAWANI_CREATE_SESSION_URL (config/payment.php:23) and AZURE_CLIENT_SECRET (config/services.php:63, the SSO secret the code reads) — both read from config but absent from backend/.env.example (which instead ships an unused AZURE_SECRET_ID).

Every 🔐 above. The critical set: APP_KEY; DB/Redis/Mail/Pusher/MinIO passwords; AWS_SECRET_ACCESS_KEY; PROMETHEUS_SCRAPE_METRICS_TOKEN; the CRM chain (CRMS_MIDDLEWARE_CLIENT_SECRET, LINK_DEV_CLIENT_SECRET, the three *_CRM_CLIENT_SECRET, CMS_CLIENT_SECRET); all Paymob keys/HMAC secrets, THAWANI_SECRET_KEY, WSPG_SECRET_KEY; PDF_SERVICE_TOKEN / pdf API_TOKEN; AZURE_CLIENT_SECRET; the two mail *_CLIENT_SECRET; FIREBASE_CREDENTIALS; GOOGLE_ANALYTICS_PRIVATE_KEY; INFOBIP_API_KEY; CURRENY_LAYER_API_KEY; OTP_TEST_CODE; and — because they shipped to the browser — NX_CLIENT_SECRET and NX_CURRENY_LAYER_API_KEY.