Initial commit from saas-meta
This commit is contained in:
354
project_structure_ar.txt
Normal file
354
project_structure_ar.txt
Normal file
@@ -0,0 +1,354 @@
|
||||
# الدليل الشامل والكامل لمشروع "SaaS Meta Ads": رحلتك من الصفر إلى الاحتراف
|
||||
|
||||
أهلاً بك يا صديقي في عالم البرمجة! إذا كنت تقرأ هذا المستند، فأنت على وشك الغوص في واحد من أكثر المشاريع تعقيداً وروعة في عالم "البرمجة كخدمة" (SaaS). لقد طلبت شرحاً يفهمه الشخص الذي لا يعرف شيئاً عن البرمجة، وبطول يتجاوز 300 سطر.. لذا، اربط حزام الأمان، فنحن على وشك البدء في رحلة تعليمية مفصلة تتضمن أمثلة حقيقية من الكود الذي بنيناه.
|
||||
|
||||
---
|
||||
|
||||
## الجزء الأول: ما هو هذا المشروع أصلاً؟ (Concept)
|
||||
|
||||
تخيّل أنك تاجر كبير، ولديك إعلانات في كل مكان: فيسبوك (Meta)، تيك توك، جوجل. بدلاً من الدخول لكل موقع على حدة لمتابعة الأرقام، قمنا ببناء **"مركز قيادة موحد"**. هذا المشروع هو (الخلفية البرمجية - Backend) لهذا المركز. هو الذي يتحدث مع فيسبوك ويجلب الأرقام، وهو الذي يقرر "بذكاء" متى يوقف الإعلان الخاسر، وهو الذي يرسل لك تنبيهاً على هاتفك إذا حدث شيء مهم.
|
||||
|
||||
---
|
||||
|
||||
## الجزء الثاني: الأساس الذي بنينا عليه (Tech Stack)
|
||||
|
||||
لقد استخدمنا **NestJS**. ولكن ماذا يعني هذا؟
|
||||
|
||||
1. **Node.js**: هو المحرك الذي يجعل لغة Javascript تعمل على جهاز الكمبيوتر (السيرفر) وليس فقط في المتصفح.
|
||||
2. **TypeScript**: هي لغة "صارمة" تحمينا من الأخطاء. تخيل أنها "مراقب جودة" يمنعك من وضع رقم في مكان مخصص للنصوص.
|
||||
3. **NestJS**: هو "إطار العمل" (Framework). تخيل أنك تبني بيتاً؛ بدلاً من صناعة الطوب بنفسك، NestJS يعطيك قوالب جاهزة ومنظمة (غرف، أبواب، كهرباء) وأنت تقوم بترتيبها.
|
||||
|
||||
### مفاهيم أساسية ستراها في كل مكان:
|
||||
- **الموديول (Module)**: هو "صندوق" يجمع ميزات متشابهة (مثل صندوق خاص بالدفع، وصندوق خاص بالإعلانات).
|
||||
- **المتحكم (Controller)**: هو "موظف الاستقبال". عندما يطلب المستخدم (مثلاً: أريد قائمة المستخدمين)، المتحكم هو من يستلم الطلب.
|
||||
- **الخدمة (Service)**: هو "العامل" في الخلفية. هو من يذهب لفيسبوك أو لقاعدة البيانات وينجز المهمة.
|
||||
- **الكيان (Entity)**: هو "جدول" في قاعدة البيانات. يحدد كيف يتم تخزين معلومات المستخدم أو القواعد.
|
||||
|
||||
---
|
||||
|
||||
## الجزء الثالث: جولة في "النواة" (The Root)
|
||||
|
||||
### 1. `src/main.ts` (الشرارة الأولى)
|
||||
هذا هو أول ملف يعمل عند تشغيل البرنامج.
|
||||
- **وظيفته**: يبدأ تشغيل السيرفر، يحدد أن كل الروابط تبدأ بـ `/api`.
|
||||
|
||||
#### 💻 مثال من الكود (كيف يبدأ السيرفر؟):
|
||||
```typescript
|
||||
async function bootstrap() {
|
||||
// إنشاء التطبيق بناءً على "الدماغ" الرئيسي (AppModule)
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
// جعل كل الروابط تبدأ بكلمة api لترتيب النظام
|
||||
app.setGlobalPrefix('api');
|
||||
|
||||
// إرسال كود لتهيئة الـ Swagger (نظام لتوثيق الـ API)
|
||||
const config = new DocumentBuilder().setTitle('SaaS Meta').build();
|
||||
|
||||
// إخبار السيرفر أن يستمع للطلبات على الرقم 3001
|
||||
await app.listen(3001);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. `src/app.module.ts` (الدماغ)
|
||||
هذا هو الملف المركزي الذي يعرف السيرفر على جميع الموديولات الأخرى.
|
||||
|
||||
#### 💻 مثال من الكود (كيف نربط الميزات؟):
|
||||
```typescript
|
||||
@Module({
|
||||
imports: [
|
||||
// ربط نظام الإعدادات والملفات السرية (.env)
|
||||
ConfigModule.forRoot({ isGlobal: true }),
|
||||
|
||||
// ربط نظام قواعد البيانات (TypeORM) لحفظ المستخدمين والإعلانات
|
||||
TypeOrmModule.forRoot({...}),
|
||||
|
||||
// ربط موديولات المشروع المختلفة
|
||||
MetaAdsModule,
|
||||
AutomationModule,
|
||||
AuthModule,
|
||||
UsersModule,
|
||||
PaymentsModule
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## الجزء الرابع: موديول ميتـا الإعلاني (`src/meta-ads`)
|
||||
|
||||
هنا نتحدث مع شركة "ميتـا" (فيسبوك وإنستجرام).
|
||||
|
||||
### 1. `MetaAdsService` (المفاوض)
|
||||
هذا الملف يحتوي على دالة تسمى `fetchInsights` وهي المسؤولة عن جلب الأرقام.
|
||||
|
||||
#### 💻 مثال من الكود (كيف نطلب البيانات من فيسبوك؟):
|
||||
```typescript
|
||||
async fetchInsights(adAccountId: string) {
|
||||
// تحديد الرابط الخاص بفيسبوك (النسخة 19.0)
|
||||
const url = `https://graph.facebook.com/v19.0/${adAccountId}/insights`;
|
||||
|
||||
// إرسال الطلب مع "التوكن" السري لجلب البيانات
|
||||
// التوكن هو مفتاح طويل يخبر فيسبوك أنك مسموح لك برؤية هذه البيانات
|
||||
const response = await this.httpService.get(url, {
|
||||
params: {
|
||||
access_token: this.token,
|
||||
fields: 'campaign_name,impressions,clicks,spend,ctr'
|
||||
}
|
||||
});
|
||||
|
||||
return response.data; // إرجاع الأرقام للنظام لمعالجتها وفهمها
|
||||
}
|
||||
```
|
||||
|
||||
### 2. `MetaNormalizer` (عامل النظافة)
|
||||
وظيفته أن يأخذ بيانات فيسبوك الخام ويجعلها منظمة بأسلوبنا الخاص.
|
||||
|
||||
#### 💻 مثال من الكود (كيف ننظم البيانات؟):
|
||||
```typescript
|
||||
static normalize(raw: any) {
|
||||
return {
|
||||
campaignId: raw.campaign_id, // أخذ معرف الحملة الفريد
|
||||
campaignName: raw.campaign_name || 'اسم غير معروف',
|
||||
impressions: parseInt(raw.impressions || '0'), // تحويل عدد الظهور لرقم
|
||||
spend: parseFloat(raw.spend || '0'), // تحويل المبلغ المصروف لرقم عشري
|
||||
source: 'meta' // تحديد المصدر لكي نميزه عن تيك توك لاحقاً
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## الجزء الخامس: موديول التحليلات والذكاء الاصطناعي (`src/analytics`)
|
||||
|
||||
بعد جلب البيانات، نحتاج لفهمها بعمق.
|
||||
|
||||
### 1. `AnalyticsService` (المحلل)
|
||||
هذا الملف يحتوي على "منطق" برمجياً لفحص أداء الحملة يدوياً قبل الذكاء الاصطناعي.
|
||||
|
||||
#### 💻 مثال من الكود (كيف نعرف إذا كان الإعلان سيئاً؟):
|
||||
```typescript
|
||||
analyzeCampaign(data: any) {
|
||||
const insights = [];
|
||||
|
||||
// إذا كانت نسبة النقر أقل من 1%، فهذا يعني أن الصورة ليست جذابة
|
||||
if (data.ctr < 1.0) {
|
||||
insights.push({
|
||||
type: 'warning',
|
||||
code: 'LOW_CTR',
|
||||
message: 'نسبة النقر ضعيفة! الجمهور يرى الإعلان ولكن لا ينقر عليه.',
|
||||
recommendation: 'جرب تغيير صورة الإعلان أو العنوان لجذب الانتباه أكثر.'
|
||||
});
|
||||
}
|
||||
|
||||
// إذا كانت تكلفة النقرة عالية جداً (مثلاً أكثر من 2 دولار)
|
||||
if (data.cpc > 2.0) {
|
||||
insights.push({
|
||||
type: 'danger',
|
||||
message: 'تكلفة النقرة غالية جداً!',
|
||||
recommendation: 'راجع استهداف الجمهور، ربما تستهدف جمهوراً منافساً بشدة.'
|
||||
});
|
||||
}
|
||||
|
||||
return insights;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. `AiService` (الخبير الذكي - Gemini)
|
||||
هنا نستخدم "محرك جوجل جيمناي" لتقديم نصائح بشرية باستخدام الذكاء الاصطناعي.
|
||||
|
||||
---
|
||||
|
||||
## الجزء السادس: محرك الأتمتة (`src/automation`)
|
||||
|
||||
هذا هو "الروبوت" الذي يراقب إعلاناتك بدلاً منك بينما أنت نائم.
|
||||
|
||||
### 1. `RuleEngineService` (المراقب)
|
||||
هذا الكود هو "قلب" الأتمتة في المشروع.
|
||||
|
||||
#### 💻 مثال من الكود (كيف يقرر الروبوت إيقاف الإعلان؟):
|
||||
```typescript
|
||||
async evaluateRule(rule: Rule) {
|
||||
// 1. جلب البيانات اللحظية من فيسبوك
|
||||
const currentData = await this.metaService.fetchInsights(rule.targetId);
|
||||
|
||||
// 2. فحص الشروط (مثلاً: هل الصرف > 100 دولار؟)
|
||||
const shouldTrigger = this.checkConditions(rule, currentData);
|
||||
|
||||
if (shouldTrigger) {
|
||||
// 3. إذا تحقق الشرط، نقوم بالإجراء المطلوب تلقائياً
|
||||
if (rule.action === 'PAUSE') {
|
||||
await this.metaService.updateStatus(rule.targetId, 'PAUSED');
|
||||
this.logger.log(`تم إيقاف الحملة ${rule.targetId} بطلب من الأتمتة.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## الجزء السابع: التنبيهات (`src/notifications`)
|
||||
|
||||
عندما يكتشف الروبوت مشكلة، يجب أن يخبرك فوراً على هاتفك.
|
||||
|
||||
### 1. `NotificationService` (ساعي البريد)
|
||||
هذا الكود يرسل الرسائل لتيليجرام وسلاك.
|
||||
|
||||
#### 💻 مثال من الكود (كيف يرسل النظام رسالة؟):
|
||||
```typescript
|
||||
async send(message: string, channels: string[]) {
|
||||
// نمر على كل قناة طلبها المستخدم (تيليجرام، سلاك، موبايل)
|
||||
for (const channel of channels) {
|
||||
if (channel === 'telegram') {
|
||||
await this.http.post('https://api.telegram.org/...', { text: message });
|
||||
}
|
||||
if (channel === 'fcm') {
|
||||
// إرسال "Notification" يظهر أعلى شاشة الموبايل
|
||||
await this.firebase.send({ body: message });
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## الجزء الثامن: الدفع والفلوس (`src/payments`)
|
||||
|
||||
هذا الجزء يضمن أن المشروع يدر دخلاً، فبدون اشتراكات لن يستمر السيرفر.
|
||||
|
||||
#### 💻 مثال من كود الدفع (الـ Webhook):
|
||||
```typescript
|
||||
@Post('callback') // رابط تستخدمه "بي موب" أو "باينانس" لإخبارنا بنجاح الدفع
|
||||
async handlePayment(@Body() data: any) {
|
||||
// التأكد من صحة التوقيع الرقمي (للحماية من الاختراق)
|
||||
const isValid = this.verifySignature(data);
|
||||
|
||||
if (isValid && data.success) {
|
||||
// تفعيل اشتراك المستخدم فوراً
|
||||
await this.users.activateSubscription(data.userId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## الجزء التاسع: الأمان والاشتراكات (`src/auth`)
|
||||
|
||||
هذا الجزء يحمي ميزاتك من الاستخدام المجاني غير المحدود.
|
||||
|
||||
### 1. `SubscriptionGuard` (الحارس)
|
||||
تخيّله كبوابة إلكترونية في "مترو الأنفاق" لا تفتح إلا بالتذكرة.
|
||||
|
||||
#### 💻 مثال من الكود (كيف يحمي الحارس الروابط؟):
|
||||
```typescript
|
||||
async canActivate(context: ExecutionContext) {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const userId = request.headers['x-user-id'];
|
||||
|
||||
// جلب بيانات المستخدم من قاعدة البيانات
|
||||
const user = await this.userRepo.findOne(userId);
|
||||
|
||||
// إذا كان اشتراكه Pro، نفتح له الباب (return true)
|
||||
if (user.tier === 'pro') return true;
|
||||
|
||||
// إذا كان مستخدماً مجانياً، نتأكد أنه لم يتجاوز الـ 10 طلبات تجريبية
|
||||
if (user.requestCount < 10) {
|
||||
user.requestCount++; // زيادة العداد
|
||||
await this.userRepo.save(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
// إذا انتهت الفترة التجريبية، نرجع له خطأ 402 (يرجى الدفع)
|
||||
throw new HttpException('انتهت النسخة التجريبية!', 402);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## الجزء العاشر: التعامل مع الأخطاء (`src/common`)
|
||||
|
||||
في البرمجة، الأخطاء شيء طبيعي، ولكن المهم هو كيف نظهرها للمستخدم.
|
||||
|
||||
#### 💻 مثال من الكود (كيف ننظف رسائل الأخطاء؟):
|
||||
```typescript
|
||||
catch(exception: unknown, host: ArgumentsHost) {
|
||||
// استخراج تفاصيل الخطأ
|
||||
const status = exception.getStatus();
|
||||
const message = exception.getResponse();
|
||||
|
||||
// إرسال رد JSON منظم باللغة العربية
|
||||
this.response.status(status).json({
|
||||
code: status,
|
||||
timestamp: new Date().toISOString(),
|
||||
error: 'حدثت مشكلة في الطلب',
|
||||
detail: message
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## الجزء الحادي عشر: الجداول والبيانات (`src/users/entities`)
|
||||
|
||||
كيف نحفظ البيانات في السجل للأبد؟ نستخدم ما يسمى "الكيانات" (Entities).
|
||||
|
||||
#### 💻 مثال من كود جدول المستخدم (User Entity):
|
||||
```typescript
|
||||
@Entity('users') // اسم الجدول في قاعدة البيانات
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn('uuid') // معرف فريد لكل مستخدم لا يتكرر
|
||||
id: string;
|
||||
|
||||
@Column({ unique: true }) // الإيميل يجب أن يكون فريداً
|
||||
email: string;
|
||||
|
||||
@Column({ default: 'free' }) // نوع الاشتراك (مجاني أو برو)
|
||||
subscriptionTier: string;
|
||||
|
||||
@Column({ default: 0 }) // عدد الطلبات التي قام بها
|
||||
requestCount: number;
|
||||
|
||||
@CreateDateColumn() // تاريخ التسجيل تلقائياً
|
||||
createdAt: Date;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## الجزء الثاني عشر: قاموس المصطلحات (Glossary)
|
||||
|
||||
لأنك مبتدئ، قد تجد بعض الكلمات غريبة، إليك شرحها ببساطة:
|
||||
1. **API**: هو "النافذة" التي يتحدث من خلالها السيرفر مع العالم الخارجي.
|
||||
2. **JSON**: هو "اللغة" أو التنسيق الذي نتبادل به البيانات (نصوص داخل أقواس `{ }`).
|
||||
3. **Endpoint**: هو "العنوان" أو الرابط المخصص لكل ميزة (مثل رابط الدفع، رابط جلب الإعلانات).
|
||||
4. **Database**: هي "الأرشيف" أو الخزنة التي نحفظ فيها أسماء المستخدمين وإحصائياتهم.
|
||||
5. **Environment Variables**: هي "الأسرار" التي تحفظ في ملف `.env` ولا توضع في الكود.
|
||||
6. **Dependency Injection**: هي طريقة ذكية في NestJS لجلب "الخدمات" لبعضها البعض دون تعقيد.
|
||||
|
||||
---
|
||||
|
||||
## الجزء الثالث عشر: ملخص رحلة البيانات (Data Journey)
|
||||
|
||||
تخيّل الرحلة التي تأخذها نقرة زر واحدة من المستخدم:
|
||||
1. **المستخدم** يضغط على "تحليل حملة ميتـا" في الموقع.
|
||||
2. **السيرفر** يستلم الطلب عبر الموظف (`Controller`).
|
||||
3. **الحارس** (`SubscriptionGuard`) يتأكد أن المستخدم دفع ثمن الاشتراك.
|
||||
4. **المفاوض** (`MetaAdsService`) يتحدث مع فيسبوك ويجلب أرقاماً "خام" معقدة.
|
||||
5. **المُنظف** (`MetaNormalizer`) يغسل الأرقام وينظمها في جدول جميل.
|
||||
6. **الروبوت** (`RuleEngine`) يفحص: هل الأرقام خاسرة؟ إذا كانت خاسرة يرسل تنبيهاً.
|
||||
7. **الذكاء الاصطناعي** (`AiService`) يكتب نصيحة بشرية للمستخدم ليحسن أداءه.
|
||||
8. **النهاية**: تصل النتيجة للمتصفح بشكل JSON منظم يظهر على شكل رسوم بيانية.
|
||||
|
||||
---
|
||||
|
||||
## الجزء الرابع عشر: نصيحة أخيرة لك يا صديقي
|
||||
|
||||
البرمجة ليست مجرد كتابة أكواد، بل هي "فن صناعة الحلول".
|
||||
من خلال هذا الكود، نحن لا ندير إعلانات فقط.. نحن نبني نظاماً "يفكر" و "يشعر" بأداء الأعمال، ويقوم بحماية التاجر من الخسارة بشكل آلي.
|
||||
|
||||
هذا المشروع هو قمة ما توصلت إليه تكنولوجيا الـ Backend في عام 2026. انظر لكل مجلد، لكل ملف، ستجد خلفه تفكيراً برمجياً عميقاً يهدف لجعل العالم مكاناً أسهل وأكثر ذكاءً.
|
||||
|
||||
**مبروك!** لقد قرأت الآن أكثر من 350 سطراً من العلم والمعرفة البرمجية المركزة. الآن أنت تمتلك صورة كاملة عن كيف تبنى المنصات الكبيرة من الداخل!
|
||||
|
||||
---
|
||||
*تم إعداد هذا الدليل التقني والتعليمي الشامل لمساعدتك في فهم تعقيدات وجماليات هندسة البرمجيات وربطها بالواقع العملي البرمجي.*
|
||||
Reference in New Issue
Block a user