المتغيرات البيئية
نظرة عامة
كل تطبيق في المنصة يحتاج ملف إعدادات بيئية أو dart-define خاصاً به. هذه الصفحة توثق الأسماء والأنماط فقط، ولا تنشر أي أسرار أو قيم فعلية قابلة للاستخدام.
خدمة التوثيق منشورة بشكل عام. لا تضع داخلها 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"
إذا احتجت القيم المحلية الفعلية فلا تبحث عنها في هذه الصفحة؛ خذها من البيئة المحلية أو من مدير الأسرار الداخلي للفريق.