Spaces:
Runtime error
Download API_REFERENCE.md from moustafa7/flwo: direct link, hf CLI and curl.
- Browser
- Download file 31.7 kB
-
https://huggingface.co/spaces/moustafa7/flwo/resolve/main/API_REFERENCE.md
- Command line
-
hf download hf://spaces/moustafa7/flwo/API_REFERENCE.md
-
curl -L -o API_REFERENCE.md https://huggingface.co/spaces/moustafa7/flwo/resolve/main/API_REFERENCE.md
DesignFlow — API Reference الكامل
Base URL:
https://api.designflow.com/api
كل الـ responses بتكونContent-Type: application/json
كل الـ timestamps بتكون ISO 8601:"2025-06-01T10:30:00.000Z"
الأخطاء دايماً بتكون:{ "error": "...", "code": "..." }
Authentication
الـ API بيستخدم JWT Bearer Tokens للـ authentication.
Authorization: Bearer <access_token>
- Access Token: عمره 15 دقيقة — يتبعت في الـ response body
- Refresh Token: عمره 7 أيام — يتخزن في
HttpOnly Cookieتلقائياً (مش بتشوفه في الـ JavaScript) - الـ cookie اسمه
refresh_tokenوبيتبعت تلقائياً مع كل request لـ/api/auth/refresh
Response Format الموحد
Success Response
{
"data": { ... }, // أو الـ object مباشرة حسب الـ endpoint
"message": "..." // اختياري
}
Error Response
{
"error": "رسالة خطأ واضحة",
"code": "ERROR_CODE_IN_CAPS",
"details": { ... } // موجود فقط في الـ validation errors
}
Validation Error Response
{
"error": "بيانات غير صحيحة",
"code": "VALIDATION_ERROR",
"details": {
"email": ["بريد إلكتروني غير صحيح"],
"password": ["كلمة المرور 8 أحرف على الأقل"]
}
}
Error Codes المحتملة
| Code | HTTP | المعنى |
|---|---|---|
VALIDATION_ERROR |
400 | بيانات مدخلة غير صحيحة |
INVALID_CREDENTIALS |
401 | بيانات تسجيل الدخول غلط |
NO_TOKEN |
401 | لم يتم إرسال access token |
TOKEN_REVOKED |
401 | الـ token اتعمله logout |
INVALID_REFRESH_TOKEN |
401 | Refresh token منتهي أو غير صحيح |
REFRESH_TOKEN_REUSE |
401 | محاولة إعادة استخدام refresh token قديم |
UNAUTHORIZED |
401 | غير مسجل دخول |
FORBIDDEN |
403 | ليس لديك صلاحية |
ACCOUNT_SUSPENDED |
403 | الحساب موقوف |
NOT_FOUND |
404 | العنصر غير موجود |
TEMPLATE_NOT_FOUND |
404 | القالب غير موجود |
ORDER_NOT_FOUND |
404 | الطلب غير موجود |
DUPLICATE_ENTRY |
409 | البريد أو الهاتف مستخدم بالفعل |
RATE_LIMIT_EXCEEDED |
429 | عدد كبير من الطلبات |
TOO_MANY_LOGIN_ATTEMPTS |
429 | محاولات دخول كثيرة |
INTERNAL_ERROR |
500 | خطأ داخلي في الخادم |
Pagination
الـ endpoints التي تدعم الـ pagination بتقبل:
| Query Param | Default | Description |
|---|---|---|
page |
1 | رقم الصفحة |
limit |
10 أو 12 | عدد العناصر في الصفحة |
وبترجع:
{
"data": [...],
"total": 45,
"page": 1,
"totalPages": 5
}
AUTH ENDPOINTS
POST /auth/register
تسجيل عميل جديد.
Rate Limit: 3 requests/hour per IP
Request: multipart/form-data (بسبب رفع الصورة)
| Field | Type | Required | Validation |
|---|---|---|---|
firstName |
string | ✅ | 2-50 حرف، حروف فقط |
lastName |
string | ✅ | 2-50 حرف، حروف فقط |
phone |
string | ✅ | format: +201234567890 |
email |
string | ✅ | valid email |
password |
string | ✅ | 8+ chars، uppercase + رقم + رمز خاص |
confirmPassword |
string | ✅ | يطابق password |
avatar |
file | ❌ | JPEG/PNG/WebP، max 5MB |
Response 201 Created:
{
"user": {
"id": "clx1234abcd",
"firstName": "Ahmed",
"lastName": "Mohamed",
"email": "ahmed@example.com",
"phone": "+201234567890",
"avatarUrl": "https://res.cloudinary.com/.../avatar.jpg",
"role": "CLIENT",
"createdAt": "2025-06-01T10:00:00.000Z"
},
"accessToken": "eyJhbGciOiJIUzI1NiJ9..."
}
+ Sets refresh_token HttpOnly Cookie
Errors:
400 VALIDATION_ERROR— بيانات غير صحيحة409 DUPLICATE_ENTRY— البريد أو الهاتف موجود429 TOO_MANY_REGISTRATIONS— تجاوز حد التسجيل
POST /auth/login
تسجيل الدخول.
Rate Limit: 5 requests/15min per IP (فاشلين فقط)
Request: application/json
{
"email": "ahmed@example.com",
"password": "MyPass@123"
}
Response 200 OK:
{
"user": {
"id": "clx1234abcd",
"firstName": "Ahmed",
"lastName": "Mohamed",
"email": "ahmed@example.com",
"role": "CLIENT",
"avatarUrl": "https://..."
},
"accessToken": "eyJhbGciOiJIUzI1NiJ9..."
}
+ Sets refresh_token HttpOnly Cookie
Errors:
400 VALIDATION_ERROR401 INVALID_CREDENTIALS— نفس الـ message للـ user غير الموجود وكلمة المرور الغلط (security)403 ACCOUNT_SUSPENDED429 TOO_MANY_LOGIN_ATTEMPTS
POST /auth/refresh
تجديد الـ access token باستخدام الـ refresh token cookie.
Request: لا يحتاج body — الـ cookie يتبعت تلقائياً
Response 200 OK:
{
"user": { ... },
"accessToken": "eyJhbGciOiJIUzI1NiJ9..."
}
+ Sets new refresh_token HttpOnly Cookie (rotation)
+ Deletes old refresh token from DB
Errors:
401 NO_REFRESH_TOKEN— مفيش cookie401 INVALID_REFRESH_TOKEN— منتهي أو غير صحيح401 REFRESH_TOKEN_REUSE— إعادة استخدام token قديم (security breach — يُعمل revoke لكل tokens)
POST /auth/logout
Requires: Authorization: Bearer <token>
تسجيل الخروج — بيحذف الـ refresh token وبيـblacklist الـ access token.
Response 200 OK:
{
"message": "تم تسجيل الخروج بنجاح"
}
+ Clears refresh_token cookie
+ Blacklists current access token in Redis
GET /auth/me
Requires: Authentication
بيانات المستخدم الحالي.
Response 200 OK:
{
"id": "clx1234abcd",
"firstName": "Ahmed",
"lastName": "Mohamed",
"email": "ahmed@example.com",
"phone": "+201234567890",
"role": "CLIENT",
"avatarUrl": "https://..."
}
USER ENDPOINTS
GET /users/profile
Requires: Authentication
Response 200 OK:
{
"id": "clx1234abcd",
"firstName": "Ahmed",
"lastName": "Mohamed",
"email": "ahmed@example.com",
"phone": "+201234567890",
"avatarUrl": "https://...",
"createdAt": "2025-06-01T10:00:00.000Z",
"_count": {
"orders": 5
}
}
PUT /users/profile
Requires: Authentication
تعديل الاسم والهاتف.
Request: application/json
{
"firstName": "Ahmed",
"lastName": "Ali",
"phone": "+201234567891"
}
Response 200 OK: نفس شكل GET /users/profile
Errors:
400 VALIDATION_ERROR409 DUPLICATE_ENTRY— رقم الهاتف موجود عند شخص آخر
PUT /users/profile/avatar
Requires: Authentication
Request: multipart/form-data
| Field | Type | Required | Validation |
|---|---|---|---|
avatar |
file | ✅ | JPEG/PNG/WebP، max 5MB |
Response 200 OK:
{
"avatarUrl": "https://res.cloudinary.com/.../new-avatar.jpg"
}
PUT /users/password
Requires: Authentication
Request: application/json
{
"currentPassword": "OldPass@123",
"newPassword": "NewPass@456"
}
Response 200 OK:
{
"message": "تم تغيير كلمة المرور بنجاح"
}
Errors:
400 VALIDATION_ERROR401 INVALID_CREDENTIALS— كلمة المرور الحالية غلط
TEMPLATES ENDPOINTS
GET /templates
قائمة القوالب المنشورة. لا يحتاج authentication.
Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
page |
number | 1 | رقم الصفحة |
limit |
number | 12 | عدد القوالب في الصفحة (max: 50) |
category |
string | — | فلتر بالفئة |
search |
string | — | بحث في العنوان والوصف |
sort |
string | newest |
newest | price_asc | price_desc |
Response 200 OK:
{
"templates": [
{
"id": "clx5678efgh",
"title": "E-Commerce Pro",
"description": "قالب احترافي للمتاجر الإلكترونية...",
"category": "تجارة",
"price": "149.00",
"previewUrl": "https://res.cloudinary.com/.../preview.jpg",
"tags": ["متجر", "عربي", "RTL"],
"defaultColors": {
"primary": "#2563EB",
"secondary": "#F8FAFC",
"accent": "#7C3AED",
"text": "#0F172A"
}
}
],
"total": 24,
"page": 1,
"totalPages": 2
}
Note:
componentsمش موجودة في القائمة — موجودة في الـ detail endpoint فقط.
Cached: ✅ Redis — 5 دقائق
GET /templates/:id
لا يحتاج authentication.
Response 200 OK:
{
"id": "clx5678efgh",
"title": "E-Commerce Pro",
"description": "قالب احترافي...",
"category": "تجارة",
"price": "149.00",
"previewUrl": "https://res.cloudinary.com/.../preview.jpg",
"demoUrl": "https://demo.designflow.com/ecom-pro",
"tags": ["متجر", "عربي", "RTL"],
"defaultColors": {
"primary": "#2563EB",
"secondary": "#F8FAFC",
"accent": "#7C3AED",
"text": "#0F172A"
},
"components": {
"sections": [
{
"id": "hero",
"label": "القسم الرئيسي",
"draggable": true,
"colorBindings": {
"background": "primary",
"heading": "text",
"button": "accent"
}
},
{
"id": "features",
"label": "المميزات",
"draggable": true,
"colorBindings": { "background": "secondary" }
}
]
}
}
Errors:
404 TEMPLATE_NOT_FOUND— غير موجود أو غير منشور
ORDERS ENDPOINTS
POST /orders
Requires: Authentication (CLIENT)
إنشاء طلب جديد بعد الشراء والتخصيص.
Request: application/json
{
"templateId": "clx5678efgh",
"customization": {
"colorTokens": {
"primary": "#E11D48",
"secondary": "#FFF1F2",
"accent": "#9333EA",
"text": "#0F172A"
},
"sections": [
{ "id": "hero", "label": "القسم الرئيسي", "draggable": true },
{ "id": "features", "label": "المميزات", "draggable": true },
{ "id": "footer", "label": "التذييل", "draggable": true }
]
},
"notes": "عايز اللون الأحمر في الـ hero button بالظبط"
}
| Field | Required | Validation |
|---|---|---|
templateId |
✅ | يجب أن يكون موجوداً ومنشوراً |
customization |
✅ | object يحتوي على colorTokens و sections |
customization.colorTokens |
✅ | object بأربع keys: primary, secondary, accent, text |
customization.colorTokens.* |
✅ | valid hex color #RRGGBB |
customization.sections |
✅ | array من الأقسام |
notes |
❌ | string, max 500 chars |
Response 201 Created:
{
"id": "clxorder123",
"orderNumber": "ORD-1717200000-A3B2C1",
"userId": "clx1234abcd",
"templateId": "clx5678efgh",
"status": "PENDING",
"customization": { ... },
"totalAmount": "149.00",
"notes": "عايز اللون...",
"createdAt": "2025-06-01T10:30:00.000Z",
"template": {
"title": "E-Commerce Pro",
"previewUrl": "https://..."
}
}
Errors:
400 VALIDATION_ERROR401 UNAUTHORIZED404 TEMPLATE_NOT_FOUND
GET /orders
Requires: Authentication (CLIENT)
طلبات العميل الحالي.
Query Parameters:
| Param | Type | Description |
|---|---|---|
page |
number | Default: 1 |
limit |
number | Default: 10 |
status |
string | PENDING | ACCEPTED | IN_PROGRESS | COMPLETED | CANCELLED |
Response 200 OK:
{
"orders": [
{
"id": "clxorder123",
"orderNumber": "ORD-1717200000-A3B2C1",
"status": "PENDING",
"totalAmount": "149.00",
"createdAt": "2025-06-01T10:30:00.000Z",
"template": {
"title": "E-Commerce Pro",
"previewUrl": "https://...",
"category": "تجارة"
},
"conversation": {
"id": "clxconv456",
"isOpen": true
}
}
],
"total": 5,
"page": 1,
"totalPages": 1
}
conversationبيكونnullلو مفيش محادثة مفتوحة.
GET /orders/:id
Requires: Authentication (CLIENT — يشوف طلباته بس)
Response 200 OK:
{
"id": "clxorder123",
"orderNumber": "ORD-1717200000-A3B2C1",
"status": "ACCEPTED",
"totalAmount": "149.00",
"notes": "...",
"createdAt": "2025-06-01T10:30:00.000Z",
"updatedAt": "2025-06-02T08:00:00.000Z",
"customization": {
"colorTokens": { "primary": "#E11D48", ... },
"sections": [ ... ]
},
"template": {
"id": "clx5678efgh",
"title": "E-Commerce Pro",
"category": "تجارة",
"previewUrl": "https://..."
},
"conversation": {
"id": "clxconv456",
"isOpen": true
}
}
Errors:
403 FORBIDDEN— لو العميل بيحاول يشوف طلب شخص آخر404 ORDER_NOT_FOUND
CHAT ENDPOINTS
GET /chat/conversations
Requires: Authentication (CLIENT)
محادثات العميل الحالي (بس المفتوحة).
Response 200 OK:
{
"conversations": [
{
"id": "clxconv456",
"isOpen": true,
"unreadCount": 2,
"lastMessage": {
"content": "سيتم البدء في التنفيذ خلال 24 ساعة",
"createdAt": "2025-06-02T09:00:00.000Z",
"senderRole": "ADMIN"
},
"order": {
"id": "clxorder123",
"orderNumber": "ORD-1717200000-A3B2C1",
"template": {
"title": "E-Commerce Pro",
"previewUrl": "https://..."
}
}
}
]
}
GET /chat/conversations/:id/messages
Requires: Authentication (CLIENT — يشوف محادثاته بس)
Query Parameters:
| Param | Type | Description |
|---|---|---|
cursor |
string | ID آخر رسالة شوفتها (للـ pagination) |
limit |
number | Default: 20 |
Response 200 OK:
{
"messages": [
{
"id": "clxmsg789",
"content": "مرحباً! تم قبول طلبك وسيتواصل معك فريقنا قريباً 🎉",
"isRead": true,
"createdAt": "2025-06-02T08:00:00.000Z",
"sender": {
"firstName": "Support",
"lastName": "Team",
"avatarUrl": "https://...",
"role": "ADMIN"
}
},
{
"id": "clxmsg790",
"content": "شكراً، متى سيتم البدء؟",
"isRead": true,
"createdAt": "2025-06-02T08:05:00.000Z",
"sender": {
"firstName": "Ahmed",
"lastName": "Mohamed",
"avatarUrl": "https://...",
"role": "CLIENT"
}
}
],
"nextCursor": "clxmsg770"
}
nextCursorبيكونnullلو مفيش رسائل قديمة أكثر.
Errors:
403 FORBIDDEN— محاولة الوصول لمحادثة شخص آخر404 CONVERSATION_NOT_FOUND
LANDING PAGE ENDPOINTS
GET /landing
لا يحتاج authentication.
محتوى الـ landing page الكامل.
Response 200 OK:
{
"hero": {
"headline": "قوالب جاهزة تُطلقك في دقائق لا أيام",
"subheadline": "اكتشف مئات القوالب الاحترافية...",
"ctaPrimaryText": "استعرض القوالب",
"ctaSecondaryText":"شاهد كيف يعمل",
"trustBadges": ["100+ قالب", "تخصيص كامل", "دعم فوري"]
},
"features": [
{ "icon": "paint", "title": "تخصيص بالسحب", "description": "..." },
{ "icon": "zap", "title": "تسليم سريع", "description": "..." }
],
"howItWorks": [
{ "step": 1, "title": "اختر قالبك", "description": "..." },
{ "step": 2, "title": "خصص ألوانه", "description": "..." },
{ "step": 3, "title": "احصل على موقعك", "description": "..." }
],
"testimonials": [
{ "name": "محمد أحمد", "role": "صاحب متجر", "text": "...", "avatar": "https://..." }
],
"footer": {
"companyDescription": "منصة تصميم احترافية...",
"socialLinks": { "facebook": "https://...", "twitter": "https://..." },
"email": "support@designflow.com"
}
}
Cached: ✅ Redis — 10 دقائق
ADMIN ENDPOINTS
كل الـ admin endpoints تحت
/api/admin
تحتاج:Authorization: Bearer <admin_token>+ role:ADMINأوSUPPORT
GET /admin/stats
Requires: ADMIN
نظرة عامة على المنصة.
Response 200 OK:
{
"totalOrders": 45,
"pendingOrders": 8,
"totalClients": 120,
"totalRevenue": "9500.00",
"monthlyRevenue": "2300.00",
"recentOrders": [
{
"id": "clxorder123",
"orderNumber": "ORD-1717200000-A3B2C1",
"status": "PENDING",
"totalAmount": "149.00",
"createdAt": "2025-06-01T10:30:00.000Z",
"user": {
"firstName": "Ahmed",
"lastName": "Mohamed",
"avatarUrl": "https://..."
},
"template": { "title": "E-Commerce Pro" }
}
],
"ordersPerMonth": [
{ "month": "يناير", "count": 5, "revenue": "650.00" },
{ "month": "فبراير","count": 8, "revenue": "1100.00" },
{ "month": "مارس", "count": 12, "revenue": "1600.00" }
]
}
GET /admin/orders
Requires: ADMIN or SUPPORT
Query Parameters:
| Param | Type | Description |
|---|---|---|
page |
number | Default: 1 |
limit |
number | Default: 20 |
status |
string | فلتر بالحالة |
search |
string | بحث باسم العميل أو رقم الطلب |
from |
string | تاريخ البداية ISO date |
to |
string | تاريخ النهاية ISO date |
Response 200 OK:
{
"orders": [
{
"id": "clxorder123",
"orderNumber": "ORD-1717200000-A3B2C1",
"status": "PENDING",
"totalAmount": "149.00",
"notes": "...",
"createdAt": "2025-06-01T10:30:00.000Z",
"user": {
"id": "clx1234abcd",
"firstName": "Ahmed",
"lastName": "Mohamed",
"email": "ahmed@example.com",
"phone": "+201234567890",
"avatarUrl": "https://..."
},
"template": {
"title": "E-Commerce Pro",
"previewUrl": "https://...",
"category": "تجارة"
},
"conversation": {
"id": "clxconv456",
"isOpen": true
}
}
],
"total": 45,
"page": 1,
"totalPages": 3
}
GET /admin/orders/:id
Requires: ADMIN or SUPPORT
Response 200 OK:
{
"id": "clxorder123",
"orderNumber": "ORD-1717200000-A3B2C1",
"status": "ACCEPTED",
"totalAmount": "149.00",
"notes": "...",
"createdAt": "2025-06-01T10:30:00.000Z",
"updatedAt": "2025-06-02T08:00:00.000Z",
"customization": {
"colorTokens": { "primary": "#E11D48", "secondary": "#FFF1F2", "accent": "#9333EA", "text": "#0F172A" },
"sections": [ { "id": "hero", "label": "القسم الرئيسي" }, ... ]
},
"user": {
"id": "clx1234abcd",
"firstName": "Ahmed",
"lastName": "Mohamed",
"email": "ahmed@example.com",
"phone": "+201234567890",
"avatarUrl": "https://...",
"_count": { "orders": 3 }
},
"template": {
"id": "clx5678efgh",
"title": "E-Commerce Pro",
"category": "تجارة",
"price": "149.00",
"previewUrl": "https://..."
},
"conversation": {
"id": "clxconv456",
"isOpen": true,
"createdAt": "2025-06-02T08:00:00.000Z"
}
}
PATCH /admin/orders/:id/status
Requires: ADMIN or SUPPORT
Request: application/json
{
"status": "ACCEPTED"
}
| Value | Description |
|---|---|
PENDING |
قيد الانتظار |
ACCEPTED |
مقبول (بيعمل auto-conversation تلقائياً) |
IN_PROGRESS |
جاري التنفيذ |
COMPLETED |
مكتمل |
CANCELLED |
ملغي |
Response 200 OK:
{
"id": "clxorder123",
"status": "ACCEPTED",
"updatedAt": "2025-06-02T08:00:00.000Z",
"conversation": {
"id": "clxconv456",
"isOpen": true
}
}
Note: لما الحالة تبقى
ACCEPTED→ بيتعمل conversation تلقائياً (لو مش موجودة) + رسالة ترحيبية تلقائية للعميل.
POST /admin/orders/:id/conversation
Requires: ADMIN or SUPPORT
فتح محادثة مع العميل يدوياً (من غير تغيير الحالة).
Request: application/json — لا يحتاج body
Response 201 Created (جديدة) أو 200 OK (موجودة):
{
"id": "clxconv456",
"orderId": "clxorder123",
"isOpen": true,
"createdAt": "2025-06-02T08:00:00.000Z",
"messages": [
{
"id": "clxmsg789",
"content": "مرحباً! تم قبول طلبك وسيتواصل معك فريقنا قريباً 🎉",
"createdAt": "2025-06-02T08:00:00.000Z",
"sender": { "firstName": "Admin", "role": "ADMIN" }
}
]
}
GET /admin/templates
Requires: ADMIN
جميع القوالب (منشورة وغير منشورة).
Response 200 OK:
{
"templates": [
{
"id": "clx5678efgh",
"title": "E-Commerce Pro",
"category": "تجارة",
"price": "149.00",
"isPublished": true,
"previewUrl": "https://...",
"tags": ["متجر", "RTL"],
"createdAt": "2025-05-01T10:00:00.000Z",
"_count": { "orders": 12 }
}
],
"total": 15
}
POST /admin/templates
Requires: ADMIN
Request: multipart/form-data
| Field | Type | Required | Validation |
|---|---|---|---|
title |
string | ✅ | 3-100 chars |
description |
string | ✅ | 10-2000 chars |
category |
string | ✅ | |
price |
number | ✅ | > 0 |
preview |
file | ✅ | JPEG/PNG/WebP, max 10MB |
demoUrl |
string | ❌ | valid URL |
tags |
string (JSON array) | ❌ | '["tag1","tag2"]' |
defaultColors |
string (JSON) | ✅ | '{"primary":"#...","secondary":"#...","accent":"#...","text":"#..."}' |
components |
string (JSON) | ✅ | '{"sections":[...]}' |
isPublished |
boolean | ❌ | Default: false |
Response 201 Created:
{
"id": "clxnewtemplate",
"title": "New Template",
"isPublished": false,
"createdAt": "2025-06-01T10:00:00.000Z"
}
PUT /admin/templates/:id
Requires: ADMIN
Request: multipart/form-data (نفس حقول POST، كلها اختيارية)
Response 200 OK: بيانات القالب المحدثة
Note: بعد التحديث بيتعمل cache invalidation تلقائياً لهذا القالب وقائمة القوالب.
DELETE /admin/templates/:id
Requires: ADMIN
Response 200 OK:
{
"message": "تم حذف القالب بنجاح"
}
Errors:
400 TEMPLATE_HAS_ORDERS— لا يمكن حذف قالب عنده طلبات
PATCH /admin/templates/:id/publish
Requires: ADMIN
نشر/إخفاء قالب.
Request: application/json
{
"isPublished": true
}
Response 200 OK:
{
"id": "clx5678efgh",
"isPublished": true,
"updatedAt": "2025-06-01T10:00:00.000Z"
}
GET /admin/landing
Requires: ADMIN
محتوى الـ landing page كاملاً.
Response: نفس شكل GET /landing — راجع الـ Landing endpoints.
PUT /admin/landing/:section
Requires: ADMIN
تعديل section معين في الـ landing page.
Path Params:
| Section | Description |
|---|---|
hero |
الـ Hero section |
features |
المميزات |
how_it_works |
كيف يعمل |
testimonials |
آراء العملاء |
footer |
التذييل |
Request: application/json — بيانات الـ section (flexible JSON)
{
"headline": "قوالب جاهزة تُطلقك في دقائق",
"subheadline": "وصف جديد...",
"ctaPrimaryText": "ابدأ الآن",
"trustBadges": ["200+ قالب", "تخصيص كامل", "دعم 24/7"]
}
Response 200 OK:
{
"section": "hero",
"content": { ... },
"updatedAt": "2025-06-01T10:00:00.000Z"
}
Note: بعد التحديث بيتعمل Redis cache invalidation فوراً.
GET /admin/conversations
Requires: ADMIN or SUPPORT
كل المحادثات.
Query Parameters:
| Param | Type | Description |
|---|---|---|
page |
number | Default: 1 |
limit |
number | Default: 20 |
isOpen |
boolean | فلتر بالحالة |
Response 200 OK:
{
"conversations": [
{
"id": "clxconv456",
"isOpen": true,
"createdAt": "2025-06-02T08:00:00.000Z",
"unreadCount": 3,
"lastMessage": {
"content": "متى سيتم البدء؟",
"createdAt": "2025-06-02T09:00:00.000Z",
"senderRole": "CLIENT"
},
"order": {
"orderNumber": "ORD-1717200000-A3B2C1",
"template": { "title": "E-Commerce Pro" },
"user": {
"firstName": "Ahmed",
"lastName": "Mohamed",
"avatarUrl": "https://..."
}
}
}
],
"total": 8
}
GET /admin/users
Requires: ADMIN
Query Parameters: page, limit, search (بالاسم أو البريد)
Response 200 OK:
{
"users": [
{
"id": "clx1234abcd",
"firstName": "Ahmed",
"lastName": "Mohamed",
"email": "ahmed@example.com",
"phone": "+201234567890",
"avatarUrl": "https://...",
"isActive": true,
"createdAt": "2025-05-01T10:00:00.000Z",
"_count": { "orders": 3 }
}
],
"total": 120,
"page": 1,
"totalPages": 12
}
SOCKET.IO EVENTS
Connection URL:
wss://api.designflow.com
Auth:{ auth: { token: "<access_token>" } }في الـ handshake
Client → Server Events
join_conversation
الانضمام لـ room محادثة معينة.
socket.emit('join_conversation', 'clxconv456')
send_message
إرسال رسالة.
socket.emit('send_message', {
conversationId: 'clxconv456',
content: 'مرحباً، متى سيتم البدء؟'
})
| Field | Validation |
|---|---|
conversationId |
مطلوب، يجب أن يكون لديك صلاحية |
content |
مطلوب، max 2000 chars |
mark_read
تعليم الرسائل كمقروءة.
socket.emit('mark_read', { conversationId: 'clxconv456' })
Server → Client Events
new_message
رسالة جديدة وصلت في الـ room.
socket.on('new_message', (message) => {
// message shape:
// {
// id: "clxmsg789",
// conversationId: "clxconv456",
// content: "...",
// createdAt: "2025-06-02T09:00:00.000Z",
// sender: { firstName, lastName, avatarUrl, role }
// }
})
message_notification
إشعار برسالة جديدة (للـ user حتى لو مش في الـ room).
socket.on('message_notification', (data) => {
// data: { conversationId, senderName, preview }
})
messages_read
الطرف الآخر قرأ الرسائل.
socket.on('messages_read', (data) => {
// data: { conversationId, readBy: "user-id" }
})
joined_conversation
تأكيد الانضمام للـ room.
socket.on('joined_conversation', (data) => {
// data: { conversationId }
})
error
خطأ في أي event.
socket.on('error', (data) => {
// data: { message: "..." }
})
GET /health
لا يحتاج authentication.
Response 200 OK:
{
"status": "ok",
"timestamp": "2025-06-01T10:00:00.000Z"
}
Frontend Integration Examples
Axios Instance مع Auto Refresh
// lib/axios.js
import axios from 'axios'
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL,
withCredentials: true, // مهم للـ refresh token cookie
})
api.interceptors.request.use((config) => {
const token = useAuthStore.getState().accessToken
if (token) config.headers.Authorization = `Bearer ${token}`
return config
})
// Auto-refresh on 401
let isRefreshing = false
let queue = []
api.interceptors.response.use(null, async (error) => {
const original = error.config
if (error.response?.status === 401 && !original._retry) {
if (isRefreshing) {
return new Promise((res, rej) => queue.push({ res, rej }))
.then(token => { original.headers.Authorization = `Bearer ${token}`; return api(original) })
}
original._retry = true
isRefreshing = true
try {
const { data } = await api.post('/auth/refresh')
useAuthStore.getState().setTokens(data.user, data.accessToken)
queue.forEach(p => p.res(data.accessToken))
queue = []
isRefreshing = false
original.headers.Authorization = `Bearer ${data.accessToken}`
return api(original)
} catch {
queue.forEach(p => p.rej(error))
queue = []
isRefreshing = false
useAuthStore.getState().logout()
return Promise.reject(error)
}
}
return Promise.reject(error)
})
Socket.IO Client
// features/chat/socketClient.js
import { io } from 'socket.io-client'
import { useAuthStore } from '../../store/authStore'
let socket = null
export function getSocket() {
if (!socket) {
socket = io(import.meta.env.VITE_API_URL, {
auth: { token: useAuthStore.getState().accessToken },
transports: ['websocket'],
autoConnect: false,
})
}
return socket
}
export function connectSocket() {
const s = getSocket()
// Update token before connecting (قد يكون اتجدد)
s.auth.token = useAuthStore.getState().accessToken
if (!s.connected) s.connect()
return s
}
export function disconnectSocket() {
if (socket?.connected) {
socket.disconnect()
socket = null
}
}
API Reference v1.0 — DesignFlow Platform