إنتقل إلى المحتوى الرئيسي

المتغيرات البيئية

نظرة عامة

كل تطبيق في المنصة يحتاج ملف إعدادات بيئية أو dart-define خاصاً به. هذه الصفحة توثق الأسماء والأنماط فقط، ولا تنشر أي أسرار أو قيم فعلية قابلة للاستخدام.

warning

خدمة التوثيق منشورة بشكل عام. لا تضع داخلها JWTs أو service-role keys أو بيانات Twilio أو مفاتيح تشغيل محلية.

تطبيقات الويب

بوابة العملاء

الملف: apps/customer/.env.local

NEXT_PUBLIC_SUPABASE_URL=<local-or-cloud-url>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key>
SUPABASE_SERVICE_ROLE_KEY=<server-only-secret>
OTP_PROVIDER=twilio
TELEGRAM_BOT_TOKEN=<telegram-botfather-token>
TWILIO_ACCOUNT_SID=<twilio-account-sid>
TWILIO_AUTH_TOKEN=<twilio-auth-token>
TWILIO_VERIFY_SERVICE_SID=<twilio-verify-service-sid>
# Alternative when OTP_PROVIDER=external:
OTP_EXTERNAL_PROVIDER_NAME=<certified-vendor-name>
OTP_EXTERNAL_BASE_URL=https://verify.vendor.example
OTP_EXTERNAL_API_KEY=<server-only-key>
OTP_EXTERNAL_SEND_PATH=/v1/verifications
OTP_EXTERNAL_VERIFY_PATH=/v1/verification-checks
NEXT_PUBLIC_ADMIN_URL=http://localhost:3002
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_DASHBOARD_URL=http://localhost:3001
NEXT_PUBLIC_VAPID_PUBLIC_KEY=<public-vapid-key>
VAPID_PRIVATE_KEY=<private-vapid-key>
VAPID_SUBJECT=mailto:support@example.com
NEXT_PUBLIC_GLITCHTIP_DSN=<optional-dsn>
GOTENBERG_URL=http://gotenberg:3000
PDF_RENDER_TIMEOUT_MS=20000
PDF_MAX_HTML_BYTES=2097152
PDF_MAX_OUTPUT_BYTES=20971520
DEMO_ACCESS_SECRET=<server-only-32-plus-character-secret>
DEMO_HUB_URL=http://localhost:3000
DEMO_DASHBOARD_URL=http://localhost:3001
DEMO_DRIVER_URL=http://localhost:8181
NEXT_PUBLIC_CUSTOMER_APK_URL=https://downloads.example.com/shambus-customer.apk
NEXT_PUBLIC_DRIVER_APK_URL=https://downloads.example.com/shambus-driver.apk
ONLINE_PAYMENTS_MODE=development

رموز الهوية ترسل عبر SMS فقط. اختر twilio أو external صراحة، واحتفظ بإثبات اعتماد المزود واتفاقية معالجة البيانات واختبار إرسال حي إلى +963 قبل النشر. لا تستخدم متغيرات Meta أو WhatsApp لمسارات OTP.

متغيرا APK اختياريان وعامان لأن الرابط يصل إلى المتصفح. تقبل صفحة التنزيل رابط https:// صالحاً فقط؛ عند حذف المتغير أو رفض قيمته تعرض الواجهة خيار استخدام نسخة الويب بدلاً من رابط تنزيل مكسور. لا تستخدم رابط GitHub افتراضياً ولا تضع رمز وصول خاصاً داخل URL.

لوحة الشركات

الملف: apps/dashboard/.env.local

NEXT_PUBLIC_SUPABASE_URL=<local-or-cloud-url>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key>
SUPABASE_SERVICE_ROLE_KEY=<server-only-secret>
NEXT_PUBLIC_APP_URL=http://localhost:3001
NEXT_PUBLIC_CUSTOMER_URL=http://localhost:3000
NEXT_PUBLIC_ADMIN_URL=http://localhost:3002
NEXT_PUBLIC_VAPID_PUBLIC_KEY=<public-vapid-key>
VAPID_PRIVATE_KEY=<private-vapid-key>
VAPID_SUBJECT=mailto:support@example.com
NEXT_PUBLIC_GLITCHTIP_DSN=<optional-dsn>
GOTENBERG_URL=http://gotenberg:3000
PDF_RENDER_TIMEOUT_MS=20000
PDF_MAX_HTML_BYTES=2097152
PDF_MAX_OUTPUT_BYTES=20971520
DEMO_ACCESS_SECRET=<same-server-only-demo-secret>
DEMO_HUB_URL=http://localhost:3000
DEMO_DASHBOARD_URL=http://localhost:3001
DEMO_DRIVER_URL=http://localhost:8181
ONLINE_PAYMENTS_MODE=development

لوحة الإدارة

الملف: apps/admin/.env.local

NEXT_PUBLIC_SUPABASE_URL=<local-or-cloud-url>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key>
SUPABASE_SERVICE_ROLE_KEY=<server-only-secret>
NEXT_PUBLIC_APP_URL=http://localhost:3002
NEXT_PUBLIC_CUSTOMER_URL=http://localhost:3000
NEXT_PUBLIC_DASHBOARD_URL=http://localhost:3001
NEXT_PUBLIC_VAPID_PUBLIC_KEY=<public-vapid-key>
VAPID_PRIVATE_KEY=<private-vapid-key>
VAPID_SUBJECT=mailto:support@example.com
NEXT_PUBLIC_GLITCHTIP_DSN=<optional-dsn>
DEMO_ACCESS_SECRET=<same-server-only-demo-secret>
DEMO_HUB_URL=http://localhost:3000
DEMO_DASHBOARD_URL=http://localhost:3001
DEMO_DRIVER_URL=http://localhost:8181

NEXT_PUBLIC_VAPID_PUBLIC_KEY يصل إلى المتصفح لإنشاء اشتراك Web Push، بينما يبقى VAPID_PRIVATE_KEY سرياً في الخادم لإرسال الإشعارات. في Docker المحلي توجد قيم تطوير افتراضية لاختبار الإشعارات على localhost فقط؛ يجب استبدالها بقيم إنتاج حقيقية وعدم إعادة استخدامها على النطاقات العامة.

GOTENBERG_URL عنوان خادمي داخلي فقط. في Compose يبقى renderer على شبكة الحاويات ولا ينشر Traefik route. تتحقق سكربتات النشر من bounds قيم PDF ومن /health ومن تحويل HTML فعلي إلى %PDF-. لا تضع رابط renderer عاماً ولا تستخدم خدمة SaaS خارجية للمستندات المالية من دون مراجعة الخصوصية والإقامة والاحتفاظ.

تطبيقات Flutter

تطبيق العملاء

الملف المرجعي: apps/mobile/customer/lib/core/config/env_config.dart

class EnvConfig {
static const String supabaseUrl = String.fromEnvironment(
'SUPABASE_URL',
defaultValue: 'http://localhost:8000',
);

static const String supabaseAnonKey = String.fromEnvironment(
'SUPABASE_ANON_KEY',
defaultValue: '',
);

static const String webApiUrl = String.fromEnvironment(
'WEB_API_URL',
defaultValue: 'http://localhost:3000',
);
}

تطبيق السائق

الملف المرجعي: apps/mobile/driver/lib/core/config/env_config.dart

class EnvConfig {
static const String supabaseUrl = String.fromEnvironment(
'SUPABASE_URL',
defaultValue: 'http://localhost:8000',
);

static const String supabaseAnonKey = String.fromEnvironment(
'SUPABASE_ANON_KEY',
defaultValue: '',
);

static const String webApiUrl = String.fromEnvironment(
'WEB_API_URL',
defaultValue: 'http://localhost:3000',
);

static const String certificatePins = String.fromEnvironment(
'CERTIFICATE_PINS',
defaultValue: '',
);
}

ملاحظة للجوال

  • لا تُشحن أسرار فعلية داخل المستودع
  • يجب تمرير CERTIFICATE_PINS في قنوات البناء الرسمية عندما يكون ذلك مطلوباً
  • القيم الفعلية تؤخذ من CI/CD أو مدير الأسرار الداخلي

Docker وبيئة التطوير المحلية

ملفات شائعة: .env, .env.local, ملفات compose غير المنشورة

POSTGRES_PASSWORD=<postgres-password>
JWT_SECRET=<jwt-secret>
ANON_KEY=<anon-key>
SERVICE_ROLE_KEY=<service-role-key>
TWILIO_MESSAGE_SERVICE_SID=<twilio-message-service-sid>
SUPABASE_PUBLIC_URL=http://localhost:8000
CUSTOMER_URL=https://shambus.com
DASHBOARD_URL=https://dashboard.shambus.com
ADMIN_URL=https://admin.shambus.com
DOCS_URL=https://docs.shambus.com
NTFY_BASE_URL=https://ntfy.shambus.com
CERTIFICATE_PINS=<sha256-pin-1,sha256-pin-2>
SUPABASE_STUDIO_PORT=3010
SUPABASE_API_PORT=8000
KONG_HTTP_PORT=8000
KONG_HTTPS_PORT=8443
GLITCHTIP_SECRET_KEY=<glitchtip-secret>
GLITCHTIP_DATABASE_URL=<glitchtip-database-url>
GF_SECURITY_ADMIN_PASSWORD=<grafana-admin-password>
MAILPIT_SMTP_PORT=1025
MAILPIT_UI_PORT=8025
NODE_ENV=development
ONLINE_PAYMENTS_MODE=development

ONLINE_PAYMENTS_MODE=development يشغل محاكاة محلية غير متصلة فقط. لا يجعل شام كاش أو البطاقة متاحين للعميل ولا يقبل webhook. في الإنتاج يجب أن تكون القيمة disabled؛ يفرض runtime التعطيل عند NODE_ENV=production ويرفض فحص النشر أي قيمة أخرى. لا تضف SHAMCASH_API_KEY أو SHAMCASH_WEBHOOK_SECRET قبل عقد تاجر رسمي ومراجعة أمن وإصدار تمكين مستقل.

تتبع الأخطاء والتنبيهات في الإنتاج

يستخدم كل سطح مشروع GlitchTip مستقلاً حتى لا تختلط أخطاء العميل مع لوحة الشركة أو الإدارة أو تطبيقات Flutter:

CUSTOMER_GLITCHTIP_DSN=https://<public-key>@errors.shambus.com/<project-id>
DASHBOARD_GLITCHTIP_DSN=https://<public-key>@errors.shambus.com/<project-id>
ADMIN_GLITCHTIP_DSN=https://<public-key>@errors.shambus.com/<project-id>
MOBILE_CUSTOMER_GLITCHTIP_DSN=https://<public-key>@errors.shambus.com/<project-id>
MOBILE_DRIVER_GLITCHTIP_DSN=https://<public-key>@errors.shambus.com/<project-id>

SMTP_HOST=<smtp-host>
SMTP_PORT=587
SMTP_USER=<smtp-user>
SMTP_PASS=<smtp-password>
SMTP_ADMIN_EMAIL=<alert-recipient>

SENTRY_DSN متغير fallback قديم فقط ولا يغني عن القيم الخمس في نشر الإنتاج. يستخدم GlitchTip STARTTLS على منفذ submission 587؛ لا تضع منفذ TLS الضمني 465 مع هذا الإعداد. تُمرر DSNs العامة إلى bundles أثناء البناء، أما مفاتيح GlitchTip وقاعدة البيانات وSMTP فتبقى في runtime فقط.

أسرار خدمات Supabase الذاتية في الإنتاج

تتطلب إصدارات Realtime وStudio/Postgres Meta الحالية ثلاثة أسرار مستقلة عن JWT_SECRET:

# 96 hex characters: openssl rand -hex 48
SECRET_KEY_BASE=<at-least-64-characters>

# Exactly 16 characters: openssl rand -hex 8
REALTIME_DB_ENC_KEY=<exactly-16-characters>

# 48 hex characters: openssl rand -hex 24
PG_META_CRYPTO_KEY=<at-least-32-characters>

PGRST_DB_SCHEMAS=public
PGRST_DB_MAX_ROWS=1000

وتحتاج طبقة التطبيق مفتاح تشفير TOTP. يمكن استخدام مفتاح مستقل، وهو المفضل، أو الرجوع إلى مفتاح التشفير الرئيسي الموجود:

ENCRYPTION_MASTER_KEY=<at-least-32-characters>
TOTP_ENCRYPTION_KEY=<optional-independent-at-least-32-characters>
BACKUP_CODE_SECRET=<independent-hmac-secret>

لا تغيّر TOTP_ENCRYPTION_KEY بعد وجود أسرار totp:v1 من دون خطة إعادة تشفير؛ فقدان المفتاح يتطلب إعادة تسجيل 2FA للحسابات المتأثرة.

  • لا تستخدم JWT_SECRET لأي من مفاتيح التشفير الثلاثة.
  • لا تدوّر REALTIME_DB_ENC_KEY بعد وجود حقول مشفرة من دون migration مخصص.
  • لا تضف storage إلى PGRST_DB_SCHEMAS؛ تستخدم الملفات Storage API وعقود RLS الخاصة بها.
  • يفرض override الإنتاجي PGRST_OPENAPI_MODE=disabled حتى لا يعرض /rest/v1/ وصف المخطط.
  • يجب أن يكون API_EXTERNAL_URL الخاص بـ GoTrue هو https://api.<domain>/auth/v1، ويطابقه GOTRUE_JWT_ISSUER.

يتحقق Compose من أطوال/وجود المفاتيح قبل استبدال الخدمات. يشرح runbook ترقية Supabase وKong النسخ والـ clone والرجوع الآمن.

متغيرات العروض الخاصة في الإنتاج

PUBLIC_SITE_MODE=coming-soon
DEMO_HUB_URL=https://demo.shambus.com
DEMO_DASHBOARD_URL=https://demo-dashboard.shambus.com
DEMO_DRIVER_URL=https://demo-driver.shambus.com
WEB_API_URL=https://web-api.shambus.com
DEMO_ACCESS_SECRET=<independent-random-secret-at-least-32-characters>
CRON_SECRET=<different-random-secret-at-least-32-characters>
MAINTENANCE_INTERVAL_SECONDS=900

يمرر عقد Compose الإنتاجي PUBLIC_SITE_MODE إلى حاوية customer بجانب OTP_PROVIDER. لذلك لا يقبل فحص الصحة OTP_PROVIDER=disabled إلا عندما يثبت أيضاً أن سياسة الإطلاق هي coming-soon؛ غياب المتغير يفشل مغلقاً.

يجب أن تختلف DEMO_ACCESS_SECRET عن CRON_SECRET وJWT_SECRET وSUPABASE_SERVICE_ROLE_KEY. لا تفعّل SHAMBUS_DEMO_ENVIRONMENT=true على بيئة الإنتاج المشتركة، لأن ذلك يحول كل الآثار الخارجية إلى محاكاة وليس عروضاً محددة فقط.

متغيرات seed الداخلي في الإنتاج

إذا كان المطلوب وجود حسابات داخلية ثابتة بعد كل تشغيل في الإنتاج، فعّل خدمة seed الداخلية عبر:

ENABLE_INTERNAL_PROD_SEEDING=true
INTERNAL_ADMIN_EMAIL=<internal-admin-email>
INTERNAL_ADMIN_PASSWORD=<internal-admin-password>
INTERNAL_ADMIN_NAME=<internal-admin-name>
INTERNAL_ADMIN_ROLE=SUPER_ADMIN
INTERNAL_QA_COMPANY_NAME_AR=<arabic-company-name>
INTERNAL_QA_COMPANY_NAME_EN=<english-company-name>
INTERNAL_QA_COMPANY_PHONE=<e164-phone>
INTERNAL_QA_COMPANY_WHATSAPP=<e164-phone>
INTERNAL_QA_COMPANY_EMAIL=<company-email>
INTERNAL_QA_COMPANY_OWNER_EMAIL=<owner-email>
INTERNAL_QA_COMPANY_OWNER_PASSWORD=<owner-password>
INTERNAL_QA_COMPANY_OWNER_NAME=<owner-name>
INTERNAL_QA_COMPANY_OWNER_ROLE=OWNER
INTERNAL_QA_PASSENGER_PHONE=<optional-e164-phone>
INTERNAL_QA_PASSENGER_NAME=<optional-passenger-name>
INTERNAL_QA_PASSENGER_EMAIL=<optional-passenger-email>
INTERNAL_QA_PASSENGER_WHATSAPP=<optional-passenger-whatsapp>
INTERNAL_QA_DRIVER_PHONE=<optional-e164-phone>
INTERNAL_QA_DRIVER_NAME=<optional-driver-name>
INTERNAL_QA_DRIVER_EMAIL=<optional-driver-email>
INTERNAL_QA_DRIVER_COMPANY_ROLE=STAFF
INTERNAL_QA_SEED_DAYS=14
INTERNAL_QA_SEED_BOOKINGS_PER_TRIP=3

ملاحظات:

  • لا تفعّل ENABLE_INTERNAL_PROD_SEEDING إلا إذا كانت القيم المطلوبة موجودة في مدير الأسرار.
  • INTERNAL_QA_DRIVER_EMAIL مطلوب فقط إذا تم تحديد INTERNAL_QA_DRIVER_PHONE.
  • INTERNAL_QA_SEED_DAYS محصور بين 0 و30، وعدد الحجوزات بين 1 و8 لكل رحلة مختارة.
  • هذا المسار لا يطبق demo seed العام. ينشئ حسابات الوصول الداخلي وشركة QA مع عالم تشغيلي محدود، ويحافظ على السجلات الموجودة عند إعادة تدوير بيانات الدخول.
  • كل باص داخلي يحصل على تخطيط مقاعد نشط ومتحقق؛ لا تصبح دالة التخطيط الخاصة بالـseed متاحة لأدوار التطبيق.

أين نحصل على القيم؟

في التطوير

  • من ملفات البيئة المحلية غير المنشورة
  • من .env.example إذا كان متاحاً
  • من المشرف التقني أو مدير الأسرار الداخلي

في الإنتاج

  • من مدير أسرار
  • من Docker/Kubernetes secrets
  • من إعدادات البيئة المشفرة في المنصة المضيفة

قواعد أمان

لا تفعل

  • لا تضف ملفات .env إلى Git
  • لا تنشر مفاتيح الخدمة أو JWT أو رموز Twilio في الوثائق
  • لا تستخدم مفاتيح الإنتاج في بيئة التطوير

افعل

  • استخدم قوالب محلية غير منشورة
  • دوّر المفاتيح بانتظام
  • افصل بين القيم العامة والقيم الخلفية
  • احصر SUPABASE_SERVICE_ROLE_KEY وTWILIO_AUTH_TOKEN في الخادم فقط

التحقق من الإعداد

# تحقق من وصول Supabase باستخدام مفاتيح التطوير المحلية لديك
curl "$NEXT_PUBLIC_SUPABASE_URL/rest/v1/" \
-H "apikey: $NEXT_PUBLIC_SUPABASE_ANON_KEY"

إذا احتجت القيم المحلية الفعلية فلا تبحث عنها في هذه الصفحة؛ خذها من البيئة المحلية أو من مدير الأسرار الداخلي للفريق.