You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
منصّة تسويق ذكية تحوّل بيانات مبيعات المتجر إلى حملات واتساب مستهدفة جغرافياً ومدعومة بالذكاء الاصطناعي
About the Project
Ala Darbak
Ala Darbak is an AI-powered marketing platform designed for small and medium-sized businesses. It connects sales data, geolocation, and artificial intelligence to transform raw sales records into targeted marketing campaigns delivered through WhatsApp, with discount coupons generated as QR codes that can be redeemed at store branches.
In short:
The store uploads its sales data → AI analyzes the data and generates a marketing campaign with an interactive question → the campaign is sent via WhatsApp to customers located within the branch radius → customers answer the question and receive a QR discount coupon by email → the coupon is redeemed in-store → campaign performance and results are automatically tracked and reported.
The Problem
Store owners have access to sales data, but often struggle to convert it into effective marketing decisions.
Traditional marketing campaigns are usually broad and untargeted, reaching everyone regardless of relevance, which increases costs and reduces effectiveness.
Businesses lack a simple and efficient way to reach customers who are actually near their branches.
Measuring the real impact of marketing campaigns is challenging, including tracking customer reach, engagement, and coupon redemption rates.
📖 فكرة المشروع
على دربك منصّة تسويق ذكية موجّهة للمتاجر الصغيرة والمتوسطة. تربط بين بيانات المبيعات و الموقع الجغرافي و الذكاء الاصطناعي لتحويل أرقام المبيعات الخام إلى حملات تسويقية مستهدفة تصل للعميل عبر واتساب، مع كوبونات خصم على شكل QR تُستبدل في الفرع.
الفكرة باختصار: المتجر يرفع مبيعاته → الذكاء الاصطناعي يحلّلها ويقترح حملة وسؤال تفاعلي → الحملة تُرسل واتساب للعملاء داخل نطاق الفرع → العميل يجاوب فيحصل على كوبون QR بالإيميل → يستبدله في الفرع → تقارير ونتائج تلقائية.
❗ المشكلة
أصحاب المتاجر يملكون بيانات مبيعات لكن لا يعرفون كيف يحوّلونها إلى قرارات تسويقية.
الحملات التقليدية عامة وغير مستهدفة — تُرسل للجميع بلا تمييز، فترتفع التكلفة وتقل النتيجة.
لا توجد وسيلة سهلة للوصول إلى العملاء القريبين فعلاً من الفرع.
صعوبة قياس أثر الحملة (كم وصل؟ كم تفاعل؟ كم استبدل العرض؟).
✅ الحل الذي يقدّمه المشروع
الخطوة
ماذا يحدث
1️⃣ رفع البيانات
المتجر يرفع المبيعات (Excel أو Google Sheets) لكل فرع
2️⃣ تحليل AI
الذكاء الاصطناعي يكتشف الأنماط: منتجات راكدة، ساعات الذروة، فرص البيع
3️⃣ اقتراح حملة
الـ AI يقترح حملة جاهزة + يولّد سؤالاً تفاعلياً
4️⃣ الاستهداف الجغرافي
تحديد العملاء داخل نطاق الفرع (Google Maps)
5️⃣ الإرسال
إرسال الحملة عبر واتساب (UltraMsg)
6️⃣ التفاعل والمكافأة
العميل يجاوب السؤال → يستلم كوبون QR بالإيميل
7️⃣ الاستبدال
الكاشير يمسح/يتحقق من الكود في الفرع
8️⃣ القياس
نتائج الحملة + تقارير شهرية PDF تلقائية
🧰 التقنيات (Tech Stack) و الـ APIs
Backend Core
التقنية
الاستخدام
Java 17 + Spring Boot 4.1.0
إطار العمل الأساسي
Spring Web (MVC)
بناء REST API (~20 Controller)
Spring Data JPA / Hibernate
الـ ORM والوصول لقاعدة البيانات
Spring Security + BCrypt
مصادقة HTTP Basic + تجزئة كلمات المرور + صلاحيات حسب الدور
The following external APIs and integrations are used in the sales records, AI analysis, campaign suggestion, holiday checking, and reporting workflow.
Integration
Type
Purpose
Related Feature
🤖 OpenAI API
External API
Used to analyze sales records, detect sales patterns, identify slow hours, generate AI summaries, and suggest smart marketing campaigns.
AIAnalysis + CampaignSuggestion
📅 Nager.Date API
External API
Used to retrieve official public holidays based on year and country code. The system uses this data to check campaign dates and improve campaign scheduling.
Holiday
📧 Email / SMTP Integration
External Service Integration
Used to send AI analysis summaries, campaign approval emails, QR coupon emails, and campaign/report notifications to store owners or customers.
AIAnalysis Email Summary + CampaignSuggestion Email + QR Coupon
📊 Google Sheets API
External API
Used to import sales records directly from Google Sheets and convert rows into sales record items inside the system.
SalesRecord Import
📁 Excel File Upload
Internal System Feature
Allows the store owner to upload sales records as an Excel file. The backend reads the file and stores its data as sales record items. This is not an external API; it is handled internally using Apache POI.
SalesRecord Upload
🗂️ مخطط الأصناف (Class Diagram)
classDiagram
direction LR
class User {
+Integer id
+String fullName
+String phone
+String email
+String password
+RoleType role
+LocalDateTime createdAt
}
class StoreOwner {
+Integer id
}
class Customer {
+Integer id
+String locationUrl
+Double latitude
+Double longitude
+Boolean locationConsent
}
class Store {
+Integer id
+String name
+String businessType
+String commercialRegisterNo
+StoreStatus status
}
class Branch {
+Integer id
+String name
+String locationUrl
+Double latitude
+Double longitude
+StoreStatus status
+Integer campaignRadiusMeters
+Integer recommendedRadiusMeters
+String openingTime
+String closingTime
}
class Subscription {
+Integer id
+SubscriptionPlanType planType
+LocalDate startDate
+LocalDate endDate
+SubscriptionStatus status
+String lemonSubscriptionId
+String variantId
+String productName
}
class Payment {
+Integer id
+Double amount
+String transactionId
+String checkoutId
+String checkoutUrl
+String paymentProvider
+PaymentStatus status
+LocalDateTime paidAt
}
class SalesRecord {
+Integer id
+String fileName
+String fileUrl
+Integer month
+Integer year
+LocalDateTime uploadedAt
}
class SalesRecordItem {
+Integer id
+String productName
+Integer quantity
+Double unitPrice
+Double totalPrice
+LocalDate saleDate
+LocalTime saleTime
}
class AIAnalysis {
+Integer id
+String topProducts
+String lowProducts
+String peakHours
+String slowHours
+String surplusProducts
+String seasonalPatterns
+String recommendation
+String aiSummary
+LocalDateTime analyzedAt
}
class CampaignSuggestion {
+Integer id
+String title
+String description
+String offerText
+CampaignType campaignType
+LocalTime suggestedStartTime
+LocalTime suggestedEndTime
+LocalDate suggestedStartDate
+LocalDate suggestedEndDate
+Integer targetCustomersCount
+Double discountValue
+String suggestedProductName
+SuggestionStatus approvalStatus
+Integer suggestionRound
}
class Campaign {
+Integer id
+String title
+String description
+String offerText
+CampaignType campaignType
+LocalDateTime startDateTime
+LocalDateTime endDateTime
+Integer targetCustomersCount
+Integer sentCount
+Integer redeemedCount
+CampaignStatus status
}
class AIQuestion {
+Integer id
+String questionText
+String optionA
+String optionB
+String optionC
+String correctOption
}
class CampaignMessage {
+Integer id
+String messageText
+Double distanceKm
+Integer durationMinutes
+String distanceText
+MessageStatus status
+LocalDateTime sentAt
}
class CustomerAnswer {
+Integer id
+String selectedOption
+Boolean correct
+LocalDateTime attemptedAt
}
class QRCode {
+Integer id
+String code
+Integer maxUsageCount
+Integer usedCount
+QRCodeStatus status
}
class QRRedemption {
+Integer id
+LocalDateTime redeemedAt
+QRRedemptionStatus status
}
class CampaignResult {
+Integer id
+Integer sentCount
+Integer redeemedCount
+Double conversionRate
+String aiSummary
+LocalDateTime createdAt
}
class MonthlyReport {
+Integer id
+Integer month
+Integer year
+Double totalSales
+Integer totalQuantity
+String topProducts
+String lowProducts
+String peakHours
+String slowHours
+String surplusProducts
+String aiSummary
+String pdfUrl
+LocalDateTime generatedAt
}
User "1" --> "0..1" StoreOwner : user_id
User "1" --> "0..1" Customer : user_id
StoreOwner "1" --> "*" Store : owns
StoreOwner "1" --> "*" Subscription : has
Subscription "1" --> "*" Payment : billed by
Store "1" --> "*" Branch : contains
Branch "1" --> "*" SalesRecord : uploads
Branch "1" --> "*" Campaign : runs
Branch "1" --> "*" MonthlyReport : reported by
SalesRecord "1" --> "*" SalesRecordItem : items
SalesRecord "1" --> "1" AIAnalysis : analyzed into
AIAnalysis "1" --> "*" CampaignSuggestion : suggests
Campaign "0..1" --> "1" CampaignSuggestion : from
Campaign "0..1" --> "1" AIQuestion : asks
Campaign "1" --> "*" CampaignMessage : sends
Campaign "1" --> "0..1" QRCode : coupon
Campaign "1" --> "0..1" CampaignResult : result
CampaignMessage "*" --> "1" Customer : to
CampaignMessage "0..1" --> "1" CustomerAnswer : answered by
CustomerAnswer "*" --> "1" Customer : by
CustomerAnswer "*" --> "1" Campaign : on
QRCode "1" --> "*" QRRedemption : redeemed by
QRRedemption "*" --> "1" Customer : by
QRRedemption "*" --> "1" Campaign : on
CampaignResult "*" --> "0..1" MonthlyReport : aggregated into
Loading
🎭 مخطط حالات الاستخدام (Use Case Diagram)
ثلاثة Actors مع حالات استخدام مشتركة مربوطة لأكثر من actor:
🔄 مخطط التدفق (Flowchart) — المشروع الكامل من التسجيل إلى التقرير الشهري
flowchart TD
%% ===== التسجيل والاشتراك =====
A1[👤 تسجيل صاحب المتجر<br/>StoreOwner Register] --> A2[التحقق من السجل التجاري<br/>Wathq API]
A2 --> A3{السجل صحيح؟}
A3 -- لا --> A1
A3 -- نعم --> A4[عرض خطط الاشتراك<br/>BASIC / PROFESSIONAL]
A4 --> A5[الاشتراك في خطة + الدفع<br/>محلي · LemonSqueezy Checkout]
A5 --> A6{الاشتراك فعّال؟}
A6 -- لا --> A4
%% ===== إعداد المتجر =====
A6 -- نعم --> B1[إنشاء متجر<br/>Create Store]
B1 --> B2[إنشاء فرع + تحديد الموقع<br/>Create Branch · lat/lng]
B2 --> B3[ضبط نطاق الحملة<br/>campaignRadiusMeters]
%% ===== بيانات المبيعات =====
B3 --> C1[رفع بيانات المبيعات]
C1 --> C2{مصدر البيانات}
C2 -- ملف Excel --> C3[رفع Excel<br/>Apache POI]
C2 -- Google Sheets --> C4[استيراد Sheet<br/>Google Sheets API]
C3 --> C5[تخزين SalesRecord + Items]
C4 --> C5
%% ===== تحليل AI واقتراح الحملة =====
C5 --> D1[تشغيل تحليل AI<br/>OpenAI gpt-4o-mini]
D1 --> D2[نتائج: منتجات راكدة · ساعات ذروة<br/>توصيات · ملخص]
D2 --> D3[توليد اقتراح حملة<br/>AI Campaign Suggestion]
D3 --> D4{صاحب المتجر يعتمد الاقتراح؟}
D4 -- يرفض --> D5[إعادة توليد اقتراح<br/>Regenerate]
D5 --> D3
%% ===== إنشاء الحملة =====
D4 -- يعتمد --> E1[إنشاء حملة من الاقتراح<br/>create-from-suggestion]
E1 --> E2{نوع الحملة}
E2 -- سؤال تفاعلي --> E3[توليد سؤال AI<br/>AIQuestion]
E2 -- عرض مباشر --> E4[بدون سؤال]
E3 --> F1
E4 --> F1[اعتماد الحملة<br/>Approve Campaign]
%% ===== الاستهداف والإرسال =====
F1 --> F2[تحديد العملاء داخل النطاق<br/>Google Maps · المسافة والوقت]
F2 --> F3[إنشاء رسائل الحملة<br/>CampaignMessage لكل عميل]
F3 --> F4[الإرسال عبر واتساب<br/>UltraMsg · start-ready]
%% ===== تفاعل العميل =====
F4 --> G1{نوع الحملة}
G1 -- عرض مباشر --> G4[توليد كوبون QR + إرساله بالإيميل<br/>ZXing + SMTP]
G1 -- سؤال تفاعلي --> G2[العميل يرد على واتساب<br/>Webhook]
G2 --> G3{الإجابة صحيحة؟}
G3 -- خطأ --> G3b[رسالة شكر بدون كوبون]
G3 -- صحيحة --> G4
%% ===== الاستبدال =====
G4 --> H1[العميل يصل الفرع]
H1 --> H2[الكاشير يتحقق من الكود<br/>cashier/check-code]
H2 --> H3{الكود صالح؟}
H3 -- لا --> H3b[رفض الاستبدال]
H3 -- نعم --> H4[تسجيل الاستبدال<br/>QRRedemption + تحديث العدّاد]
%% ===== النتائج والتقارير =====
H4 --> I1[احتساب نتائج الحملة<br/>CampaignResult]
G3b --> I1
I1 --> I2[تجميع النتائج شهرياً]
I2 --> I3[توليد التقرير الشهري<br/>MonthlyReport]
I3 --> I4[ملخص AI + PDF<br/>OpenAI + OpenHTMLtoPDF]
I4 --> I5[📧 تحميل التقرير<br/>send-email/reportId]
classDef ai fill:#1F5C4D,color:#fff;
classDef ext fill:#8a5a00,color:#fff;
class D1,D3,E3,I4 ai;
class A2,A5,C4,F2,F4,G4 ext;
Loading
🔐 الأدوار والصلاحيات
الدور
الصلاحيات
CUSTOMER
استقبال الحملات، الإجابة، استبدال الكوبونات، إدارة موقعه وبياناته
STORE_OWNER
إدارة المتاجر/الفروع، رفع المبيعات، تحليل AI، إنشاء وإرسال الحملات، الاشتراكات، التقارير
ADMIN
الإشراف على المستخدمين والاشتراكات وتشغيل المهام النظامية
المصادقة: HTTP Basic Auth (تسجيل الدخول بالإيميل) + كلمات مرور مجزّأة بـ BCrypt + فحص ملكية الكائنات على مستوى الخدمات.
🚀 التشغيل محلياً
# 1) قاعدة البيانات
CREATE DATABASE ala_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;# 2) الإعدادات في src/main/resources/application.properties# spring.datasource.url=jdbc:mysql://localhost:3306/ala_db# (ضع مفاتيح الـ APIs في application-secrets.properties)# 3) التشغيل
./mvnw spring-boot:run
# التطبيق يعمل على http://localhost:8080
ملاحظة: الجداول تُنشأ تلقائياً عبر spring.jpa.hibernate.ddl-auto=update.
☁️ النشر (Deployment)
منشور على AWS Elastic Beanstalk (Corretto 17, SingleInstance) مع قاعدة RDS MySQL 8 بمنطقة eu-central-1 (Frankfurt).