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

إعداد البيئة و .env

يغطّي هذا الدليل كيفية حمل بيانات اعتماد DZBuild API بأمان إلى تطبيقك — تطوير محلي، staging، إنتاج. سواء تبني واجهة Node.js، back-office Laravel/Symfony، خط بيانات Python، خدمة Go صغيرة، أو دالة edge serverless، القواعد ذاتها.

ما تحتاج تخزينه

لتكامل واجهة / back-office نموذجي:

المتغيرمثالملاحظات
DZBUILD_API_KEYdzpk_live_aB3xT9...سر مفتاح المنصة. عامله ككلمة مرور.
DZBUILD_API_BASEhttps://api.dzbuild.app/v1عنوان القاعدة. استخدم host الحافة في الإنتاج، لا dzbuild.com/api/v1 (هو alias فقط).
DZBUILD_WEBHOOK_SECRETdzwh_sec_...سر لكل webhook يعود من التسجيل. للتحقق من X-DZ-Signature.

لـ تدفق المفتاح العام (signups / events من عميل عام):

المتغيرمثالملاحظات
DZBUILD_PUBLIC_KEY_IDdzpub_live_...آمن للشحن في كود العميل (المعرّف عام، السر لا)
DZBUILD_SIGNING_SECRETsig_...خادمي فقط — لتوقيع HMAC لكل جسم طلب

ملفات .env

النمط الأبسط:

# .env (في جذر مشروعك، gitignored)
DZBUILD_API_KEY=dzpk_live_xxxxxxxxxxxxxxxx
DZBUILD_API_BASE=https://api.dzbuild.app/v1
DZBUILD_WEBHOOK_SECRET=dzwh_sec_xxxxxxxxxxxxxxxx
# .gitignore
.env
.env.local
.env.*.local

ضع ملف .env.example بقيم placeholder ليعرف المطورون الآخرون ما يضبطون:

# .env.example (ملتزَم بـ git)
DZBUILD_API_KEY=dzpk_live_REPLACE_ME
DZBUILD_API_BASE=https://api.dzbuild.app/v1
DZBUILD_WEBHOOK_SECRET=dzwh_sec_REPLACE_ME

تحميل .env لكل لغة

Node.js / Next.js / Express

// next.config.js — Next.js يُحمّل .env و .env.local و .env.production تلقائيًا
// لـ Node عادي:
import 'dotenv/config';
const key = process.env.DZBUILD_API_KEY;

Python

# pip install python-dotenv
from dotenv import load_dotenv
import os
load_dotenv()
key = os.environ['DZBUILD_API_KEY']

PHP / Laravel

// Laravel يُحمّل .env تلقائيًا
$key = env('DZBUILD_API_KEY');

// PHP عادي:
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$key = $_ENV['DZBUILD_API_KEY'];

Go

// go get github.com/joho/godotenv
godotenv.Load()
key := os.Getenv("DZBUILD_API_KEY")

Flutter / موبايل

لا تشحن مفتاح المنصة في تطبيقك المحمول. بدلًا من ذلك:

  1. ينادي تطبيقك المحمول خادمك الخلفي.
  2. خادمك الخلفي يحمل المفتاح ويُمرّر الطلبات إلى DZBuild.

إن احتجت أن يتحدث العميل المحمول مع DZBuild مباشرة (مثلًا لـ signups)، استخدم تدفق المفتاح العام — يُشحن فقط معرّف المفتاح العام، لا السر. انظر نقاط المفتاح العام.

بيئات الإنتاج

في الإنتاج لا تستعمل ملف .env. استعمل مدير الأسرار الأصلي للمنصة:

Vercel / Netlify / Cloudflare Pages

المشروع → الإعدادات → Environment Variables
DZBUILD_API_KEY = dzpk_live_...
DZBUILD_API_BASE = https://api.dzbuild.app/v1
DZBUILD_WEBHOOK_SECRET = dzwh_sec_...

علّم متغيرات الإنتاج في scope "Production". متغيرات staging في "Preview" أو بيئة منفصلة.

Cloudflare Workers

wrangler secret put DZBUILD_API_KEY
# (الصق القيمة عند الطلب)

متاح في الـ worker كـ env.DZBUILD_API_KEY (مع [vars] في wrangler.toml).

AWS Lambda / API Gateway

استعمل AWS Secrets Manager أو Parameter Store:

import boto3, json
secret = json.loads(
boto3.client('secretsmanager').get_secret_value(SecretId='dzbuild/prod')['SecretString']
)
key = secret['DZBUILD_API_KEY']

لا تخزّن المفتاح في Lambda env vars بنص واضح (يظهر في سجلات CloudTrail). أحل من Secrets Manager.

Docker / Docker Compose

# docker-compose.yml
services:
app:
image: yourapp:latest
env_file:
- .env.production # غير ملتزَم
environment:
- NODE_ENV=production

لـ Kubernetes استعمل Secret:

apiVersion: v1
kind: Secret
metadata:
name: dzbuild-creds
type: Opaque
stringData:
DZBUILD_API_KEY: dzpk_live_...
DZBUILD_WEBHOOK_SECRET: dzwh_sec_...

ثم أحل في النشر:

envFrom:
- secretRef:
name: dzbuild-creds

GitHub Actions

# .github/workflows/deploy.yml
env:
DZBUILD_API_KEY: ${{ secrets.DZBUILD_API_KEY }}

اضبط السر في Repo → Settings → Secrets and variables → Actions.

مفاتيح dev مقابل production

أنشئ دائمًا مفتاحين منفصلين:

  • واحد بالاسم dev أو staging — للاستخدام في .env.local / بيئات dev
  • واحد بالاسم production — يُستعمل فقط في نشر الإنتاج الفعلي

إن تسرّب مفتاح dev، تحرق dev فقط. بيانات الإنتاج تبقى سليمة.

# لوحة التحكم → Developer → API Keys
+ إنشاء مفتاح منصة → الاسم "myapp-dev"، الصلاحيات: products:read, orders:read, orders:write
+ إنشاء مفتاح منصة → الاسم "myapp-prod"، الصلاحيات: products:read, orders:read, orders:write

نفس الصلاحيات على كليهما، فقط أسماء مختلفة.

أسرار Webhooks

عند تسجيل webhook تتضمن الاستجابة secret:

curl -X POST 'https://api.dzbuild.app/v1/webhooks' \
-H "Authorization: Bearer $DZBUILD_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"url": "https://yourapp.com/webhook",
"events": ["order.created", "order.confirmed"]
}'

الاستجابة:

{
"data": {
"id": 42,
"url": "https://yourapp.com/webhook",
"secret": "dzwh_sec_aB3xT9...", ← خزّنه في DZBUILD_WEBHOOK_SECRET
"events": ["order.created", "order.confirmed"]
}
}

هذا secret يظهر مرة واحدة — احفظه فورًا في مدير أسرارك. إن فقدته، احذف الـ webhook وسجّل واحدًا جديدًا.

استعمل السر للتحقق من كل تسليم webhook:

// معالج Express webhook
app.post('/webhook', (req, res) => {
const sig = req.headers['x-dz-signature'];
const ts = req.headers['x-dz-timestamp'];
const body = req.rawBody; // ⚠️ خام، لا parsed
const expected = crypto
.createHmac('sha256', process.env.DZBUILD_WEBHOOK_SECRET)
.update(`${ts}.${body}`)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(401).send('bad signature');
}
// ... عالج الحدث
});

انظر التحقق من التواقيع لشيفرة كاملة بـ 5 لغات.

تدفق المفتاح العام (متصفح/موبايل)

إن احتجت نداء DZBuild مباشرة من المتصفح أو تطبيق محمول لنقاط محدودة (تتبع signups، تتبع events)، استخدم تدفق المفتاح العام. فقط معرّف المفتاح العام يُشحن في كود العميل — سر التوقيع يبقى على خادمك الخلفي ويوقّع كل جسم طلب.

// كود المتصفح — آمن
const PUBLIC_KEY_ID = "dzpub_live_xxxx"; // التزامه في كود العميل لا بأس به

// احصل على توقيع من خادمك (الذي يحمل DZBUILD_SIGNING_SECRET)
async function trackSignup(email, externalId) {
const nonce = crypto.randomUUID();
const body = JSON.stringify({ email, external_user_id: externalId, source: 'web', nonce });
const ts = Math.floor(Date.now() / 1000);

// خادمك الخلفي يوقّعه (لا تفعل ذلك أبدًا في المتصفح)
const { signature } = await fetch('/sign-dz-event', {
method: 'POST',
body: JSON.stringify({ body_hash_input: body, ts, nonce })
}).then(r => r.json());

await fetch('https://api.dzbuild.app/v1/signups', {
method: 'POST',
headers: {
'Authorization': `DZ-Public ${PUBLIC_KEY_ID}`,
'X-DZ-Timestamp': ts.toString(),
'X-DZ-Nonce': nonce,
'X-DZ-Signature': signature,
'Content-Type': 'application/json'
},
body
});
}

سر التوقيع لا يغادر خادمك أبدًا. معرّف المفتاح العام يمكن لأي أحد فحصه — وهذا بقصد.

نفق dev محلي للـ webhooks

تحتاج webhooks DZBuild URL HTTPS عام. للاختبار محليًا استعمل tunnel:

# ngrok
ngrok http 3000

# Cloudflare Tunnel
cloudflared tunnel --url http://localhost:3000

# tailscale serve
tailscale serve https / http://localhost:3000

سجّل URL الـ tunnel كهدف webhook. حدّثه كلما أُعيد تشغيل الـ tunnel (ngrok مجاني يغير URL في كل مرة؛ ادفع 8$ شهريًا لـ subdomain ثابت).

سياسة التدوير

دوّر المفاتيح:

  • ربع سنوي لمفاتيح الإنتاج (ضع تذكير في التقويم)
  • فورًا إن احتمل أن مفتاحًا تسرّب (التزم بـ git، صورة شاشة، أُرسل في chat)
  • عند مغادرة عضو فريق إن كان لديه وصول لمدير الأسرار

إجراء التدوير:

  1. أنشئ مفتاحًا جديدًا في اللوحة بنفس الصلاحيات.
  2. حدّث مدير الأسرار / متغيرات البيئة إلى المفتاح الجديد.
  3. انشر. تحقّق من حركة المفتاح الجديد عبر GET /v1/usage.
  4. بعد تأكيد 24 ساعة من حركة نظيفة على الجديد، ألغِ القديم: DELETE /v1/keys/{old_key_id} أو من اللوحة.

أخطاء شائعة

الخطأما يحدثالإصلاح
التزام .env في gitالمفتاح صار في تاريخ git إلى الأبد؛ دوّره فورًاgit filter-repo لا يُصلح forks/clones؛ اعتبره متسربًا
استخدام مفتاح المنصة في كود متصفحالعملاء يقرؤون network tab → يرونه ويسرقونهانقله إلى back-end / serverless؛ دوّره
Hardcode dzpk_live_... في sourceنفس الأمراستعمل env vars؛ دوّر
نفس المفتاح لـ dev وprodخطأ dev يضرب بيانات prodأنشئ مفتاحين؛ لا تشارك أبدًا
فقدان سر webhookلا يمكن التحقق من التسليماتاحذف الـ webhook، سجّل غيره
تسجيل مفتاح API في سجلات التطبيقمدققون / شاحنو سجلات / كل من له وصول للسجل يراهredact secrets في إعدادات logger؛ دوّر

قائمة سريعة قبل الإطلاق

  • .env في .gitignore (ولم يُلتزَم سهوًا)
  • مفتاح الإنتاج اسمه prod ويُستعمل فقط في prod
  • مفتاح الـ dev اسمه dev ويُستعمل فقط في dev/staging
  • أسرار webhooks في مدير أسرار، ليس في الكود
  • رأس Authorization على كل نداء API من خادمك الخلفي
  • كود المتصفح لا يرى dzpk_live_* (فقط dzpub_live_* إن استعملت تدفق المفتاح العام)
  • التحقق من التوقيع مفعّل على نقطة webhook
  • لديك تذكير تدوير مفاتيح في تقويمك
  • لديك logging لا يلتقط أجسام الطلبات الكاملة (قد تتضمن مفاتيح API في رؤوس العميل)