إعداد البيئة و .env
يغطّي هذا الدليل كيفية حمل بيانات اعتماد DZBuild API بأمان إلى تطبيقك — تطوير محلي، staging، إنتاج. سواء تبني واجهة Node.js، back-office Laravel/Symfony، خط بيانات Python، خدمة Go صغيرة، أو دالة edge serverless، القواعد ذاتها.
ما تحتاج تخزينه
لتكامل واجهة / back-office نموذجي:
| المتغير | مثال | ملاحظات |
|---|---|---|
DZBUILD_API_KEY | dzpk_live_aB3xT9... | سر مفتاح المنصة. عامله ككلمة مرور. |
DZBUILD_API_BASE | https://api.dzbuild.app/v1 | عنوان القاعدة. استخدم host الحافة في الإنتاج، لا dzbuild.com/api/v1 (هو alias فقط). |
DZBUILD_WEBHOOK_SECRET | dzwh_sec_... | سر لكل webhook يعود من التسجيل. للتحقق من X-DZ-Signature. |
لـ تدفق المفتاح العام (signups / events من عميل عام):
| المتغير | مثال | ملاحظات |
|---|---|---|
DZBUILD_PUBLIC_KEY_ID | dzpub_live_... | آمن للشحن في كود العميل (المعرّف عام، السر لا) |
DZBUILD_SIGNING_SECRET | sig_... | خادمي فقط — لتوقيع 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 / موبايل
لا تشحن مفتاح المنصة في تطبيقك المحمول. بدلًا من ذلك:
- ينادي تطبيقك المحمول خادمك الخلفي.
- خادمك الخلفي يحمل المفتاح ويُمرّر الطلبات إلى 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)
- عند مغادرة عضو فريق إن كان لديه وصول لمدير الأسرار
إجراء التدوير:
- أنشئ مفتاحًا جديدًا في اللوحة بنفس الصلاحيات.
- حدّث مدير الأسرار / متغيرات البيئة إلى المفتاح الجديد.
- انشر. تحقّق من حركة المفتاح الجديد عبر
GET /v1/usage. - بعد تأكيد 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 في رؤوس العميل)