نموذج تواصل ثنائي اللغة (عربي/إنجليزي) + لوحة تحكم داخلية لفريق إتقان.
- الواجهة العامة (
/): نموذج بأسلوب Typeform، 5 فئات، حقول ديناميكية، شاشة شكر برقم مرجعي. - لوحة التحكم (
/admin): مراجعة الطلبات، تغيير الحالات، تعيين مسؤول، ملاحظات داخلية، سجل نشاط، تصدير CSV. - بناء النموذج (
/admin/settings/form-builder): تعديل الفئات والحقول بدون كتابة كود. - Stack: Next.js 15 App Router · TypeScript · Tailwind · Supabase · Resend · Vercel.
npm install
cp .env.example .env.local
# املأ المتغيرات (انظر القسم التالي)
npm run dev # http://localhost:3000كل المتغيرات موصوفة في .env.example. القيم التي تبدأ بـ NEXT_PUBLIC_ مرئية في المتصفح؛ الباقي لا يخرج من الخادم.
| المتغير | للمطلوب؟ | المصدر |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
نعم | Supabase Dashboard → Project Settings → API |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
نعم | نفس المكان (publishable key) |
SUPABASE_SERVICE_ROLE_KEY |
نعم | نفس المكان → Secret keys (يبدأ بـ sb_secret_...). لا تُشارَك ولا تُرفع إلى GitHub. |
NEXT_PUBLIC_SITE_URL |
نعم | رابط النشر (https://join.itqan.dev) أو رابط Vercel المؤقت |
RESEND_API_KEY |
اختياري | resend.com/api-keys. بدونها لن يُرسَل بريد التأكيد. عنوان المرسِل ([email protected]) واسم المرسِل بالعربي/الإنجليزي يعيشان في src/lib/notify/email.ts. |
SLACK_WEBHOOK_URL |
اختياري | Slack App → Incoming Webhooks. بدونه لن يُنبَّه الفريق. |
NEWSLETTER_PROXY_URL |
اختياري | الافتراضي https://itqan.dev/api/newsletter/subscribe/ (الـ endpoint الحالي لنشرة إتقان/MailerLite). |
MAILERLITE_API_KEY + MAILERLITE_GROUP_ID |
اختياري | عند ضبطه يُستخدم مباشرةً بدل البروكسي. |
-
تطبيق الميجريشنز: من Supabase Dashboard → SQL Editor شغّل الملفات بالترتيب:
supabase/migrations/0001_init.sqlsupabase/migrations/0002_seed_statuses.sqlsupabase/migrations/0003_seed_form_schema.sql
بديل: شغّلها عبر Supabase CLI أو عبر MCP.
-
Authentication → URL Configuration:
- Site URL =
https://join.itqan.dev(عند الإنتاج) - Redirect URLs: أضف (كل سطر):
http://localhost:3000/admin/auth/callbackhttps://crm-itqan-community.vercel.app/admin/auth/callback(رابط Vercel المؤقت)https://join.itqan.dev/admin/auth/callback
- Site URL =
-
Authentication → Providers → Email: تأكد أن Enable Email Provider مفعّل. اترك OTP/Magic Link افتراضياً.
-
بوابة الدخول (allowed_emails): يبدأ النظام بـ
[email protected]كأدمن (من seed). تضيف البقية من/admin/settingsبعد أول دخول.
- api.slack.com/apps → Create New App → From scratch.
- اسم التطبيق:
Itqan CRM؛ اختر workspace إتقان. - القائمة اليسرى → Incoming Webhooks → فعّلها → Add New Webhook to Workspace → اختر القناة (مثلاً
#new-signups). - انسخ الرابط (
https://hooks.slack.com/services/...) وضعه فيSLACK_WEBHOOK_URL.
بدون هذا المتغير، النظام يعمل طبيعياً ولا يرسل إشعارات Slack.
- أنشئ حساب على resend.com.
- Domains → Add Domain →
itqan.dev→ أضف سجلات DNS (SPF + DKIM) المطلوبة. - بعد التحقق، API Keys → Create API Key بصلاحية Sending access.
- ضع المفتاح في
RESEND_API_KEY. - تأكد أن
RESEND_FROM_EMAIL(الافتراضي[email protected]) يشير لنطاق موثّق.
أول مرة:
- vercel.com/new → اختر مستودع GitHub
itqan-community/crm. - Framework Preset: Next.js (كشف تلقائي)، Root:
./. - Environment Variables → ألصق قيم من .env.example مع القيم الفعلية. المتغير
NEXT_PUBLIC_SITE_URLابدأ بـhttps://<project>.vercel.appثم حدّثه لاحقاً. - Deploy. الدفعات اللاحقة لـ
mainتنشر تلقائياً.
ربط الدومين join.itqan.dev:
- Vercel → Project → Settings → Domains → Add →
join.itqan.dev. - سيعطيك Vercel سجل CNAME (عادةً
cname.vercel-dns.com). أضفه في DNS مزوّد نطاقitqan.dev. - بعد التحقق، حدّث
NEXT_PUBLIC_SITE_URLإلىhttps://join.itqan.devوأعد النشر. - حدّث Supabase Auth → URL Configuration بإضافة الدومين الجديد.
src/
├── app/
│ ├── page.tsx # النموذج العام
│ ├── layout.tsx, globals.css
│ ├── api/submissions/route.ts # POST → يُدرج في DB + يرسل الإشعارات
│ └── admin/
│ ├── layout.tsx, page.tsx # قائمة الطلبات
│ ├── login/, auth/callback/ # Magic Link flow
│ ├── submissions/[id]/ # تفاصيل طلب
│ ├── settings/ # حالات + فريق + form-builder
│ └── export/route.ts # CSV
├── components/
│ ├── form/ # يبني النموذج من تعريف قاعدة البيانات
│ └── admin/ # جداول، حوارات، StatusBadge…
├── lib/
│ ├── supabase/{server,client,admin}.ts
│ ├── form-schema.ts, validation.ts, i18n.ts
│ ├── admin-queries.ts, admin-actions.ts
│ └── notify/{slack,email,newsletter}.ts
├── middleware.ts # يحمي /admin/*
└── types/database.ts # يطابق الميجريشن الأولى
supabase/migrations/0001_init.sql # الجداول + RLS + Triggers
supabase/migrations/0002_seed_statuses.sql
supabase/migrations/0003_seed_form_schema.sql
ثلاث كتل مفصولة:
- تعريف النموذج —
form_categories,form_fields. يتحكم بها الأدمن من الـ Form Builder. - بيانات الإرسال —
submissions(metadata)،submission_answers(إجابة لكل حقل مع snapshot للاسم والعنوان ليبقى العرض صحيحاً حتى بعد تعديل الحقل). - الفريق والتعاون —
team_members,allowed_emails,statuses,notes,activity_log.
جميع الجداول محمية بـ RLS. الإدراج في submissions + submission_answers مفتوح للعامة (النموذج عام)، والباقي مقصور على team_members. انظر supabase/migrations/0001_init.sql لمزيد من التفاصيل.
npm run dev # تطوير
npm run build # بناء إنتاج
npm run start # تشغيل بناء إنتاج محلياً
npm run lint # ESLint
npm run typecheck # tsc --noEmit