arc42 §6c — تدفقات بيانات الميزات: التجارة والإدارة
الحالة: مسودة v0.1 · التاريخ: 2026-07-20
يغطي: SRC-BRD §7.1 — الدفع · السوق الإلكتروني (marketplace) · الإدارة · التقارير · الإشعارات
وثيقة مرافقة: 06b-feature-flows-core.md · 06-runtime-view.md
⚠️ كل تدفق في هذه الوثيقة مشروط بـ
R-01(ترخيص SAMA). إذا لم يكن مسموحًا لـ Qwizin بحيازة الأموال وصرفها، فإن طوبولوجيا الدفع تتغيّر — لا الميزات، بل مَن يحرّك المال. جميع التدفقات أدناه مرسومة وفق Model B (مزوّد خدمات دفع مرخّص PSP يحرّك الأموال؛ وQwizin تنقل التعليمات فقط)، وهو الوضع الأقل مخاطرة بغضّ النظر عن الإجابة القانونية.
فهرس التدفقات#
| ميزة BRD §7.1 | التدفق |
|---|---|
| دفع الاستشارة | C-01 |
| دفع الطلب المخصّص | F-08 في 06b |
| دفع اشتراك المزوّد | C-02 |
| دفع الإدراج المميّز (featured) | C-03 |
| الإدراجات المميّزة (أثر الترتيب) | C-04 |
| التحويل للمزوّد (payout) للمستشارين والمزوّدين | C-05 |
| إدارة متعددة الأدوار · اعتماد المستخدمين | C-06 |
| إدارة المحتوى · إدارة المستشارين والمزوّدين | C-07 |
| مراقبة المدفوعات · التقارير · لوحة المعلومات | C-08 |
| الإشعارات (BRD §13 التبعيات 8/12/13) | C-09 |
C-00 — طوبولوجيا تدفق الأموال (Model B)#
تصف SRC-BRD §9.4 تدفق الإيرادات العميل → منصة Qwizin → المزوّد/المستشار. هذا هو Model A، وهو الشكل الذي يستدعي الترخيص.
flowchart TB
subgraph MA["❌ Model A — Qwizin holds funds"]
direction LR
CA["👤 Customer"] -->|pays| QA["Qwizin<br/>merchant account"]
QA -->|"holds balance"| QB[("Qwizin<br/>ledger")]
QB -->|disburses| PA["🎓 Consultant"]
end
subgraph MB["✅ Model B — Qwizin never touches funds"]
direction LR
CB["👤 Customer"] -->|pays| PSP["💳 SAMA-licensed PSP"]
PSP -->|"split settlement"| PB["🎓 Consultant<br/><i>sub-merchant under<br/>PSP's licence</i>"]
PSP -->|"commission"| QC["Qwizin<br/><i>separate merchant txn</i>"]
QD["Qwizin API"] -.->|"transmits split<br/>instructions only"| PSP
end
style MA fill:#fde8e8,stroke:#c94a4a
style MB fill:#e8f5e9,stroke:#2d8659
| Model A | Model B ✅ | |
|---|---|---|
| الأموال تستقر في حساب تتحكم فيه Qwizin | نعم | لا |
| Qwizin تدير سجل أرصدة (ledger) | نعم | لا |
| الوضع التنظيمي المرجّح | مؤسسة دفع | مزوّد تقنية |
| onboarding المستشار | مشكلة Qwizin | عملية KYC/AML لدى الـ PSP |
القرار: التصميم وفق Model B. إذا أكّدت الاستشارة القانونية لاحقًا أن Model A مسموح، فالانتقال إليه مباشر وبسيط. أما العكس — اكتشاف الحاجة إلى ترخيص في منتصف البناء — فهو الاتجاه المكلف. لا تبنِ ledger بأرصدة مملوكة للمستخدمين حتى يُجاب
R-01.
معايير اختيار بوابة الدفع (gateway) الناتجة عن هذه التدفقات#
يغذّي OQ-01. أي gateway يخفق في أي من هذه المعايير يُستبعد:
| المتطلب | التدفق المصدر |
|---|---|
| دعم mada | واقع السوق السعودي |
| الفصل بين authorize / capture / void (حجز / تحصيل / إلغاء) | C-01 — يحلّ CONF-02 |
| الاسترداد، الكامل والجزئي | C-01, F-08 |
| المدفوعات المقسّمة (split payments) في marketplace / onboarding التجار الفرعيين (sub-merchant) | C-05 — Model B |
| فوترة متكررة مع منطق إعادة المحاولة | C-02 |
| webhooks موقّعة وقابلة لإعادة التشغيل | الكل |
| حقول مستضافة (hosted fields) أو إعادة توجيه (بيانات البطاقة لا تمرّ بـ Qwizin إطلاقًا) | تقليل نطاق PCI |
C-01 — دفع الاستشارة#
التسلسل التفصيلي في Flow 3. مُلخَّص هنا على شكل آلة حالات (state machine)، لأن الحالات هي ما يتفاعل معه بقية النظام.
stateDiagram-v2
[*] --> pending_payment: Booking created,<br/>slot locked
pending_payment --> awaiting_consultant: 💳 AUTHORIZE (hold)<br/><i>funds NOT taken</i>
pending_payment --> abandoned: Payment window expires<br/>→ release slot
awaiting_consultant --> confirmed: Consultant accepts<br/>→ 💳 CAPTURE
awaiting_consultant --> declined: Consultant rejects<br/>→ 💳 VOID
awaiting_consultant --> expired: SLA timer elapses<br/>→ 💳 VOID + release slot
confirmed --> completed: Session held<br/>→ eligible for payout
confirmed --> no_show_customer: Customer absent
confirmed --> no_show_consultant: Consultant absent<br/>→ 💳 REFUND
confirmed --> cancelled_by_customer: → refund per policy ⚠
confirmed --> failed_technical: Session never established<br/>→ 💳 REFUND ⚠
completed --> [*]
declined --> [*]
expired --> [*]
note right of awaiting_consultant
AUTHORIZE not CAPTURE.
This is the fix for CONF-02 —
money is never taken for a
service not yet agreed.
end note
note right of cancelled_by_customer
⚠ Refund policy UNDEFINED
in all source documents.
Free cancellation window?
Partial refund tiers?
→ OQ-05
end note
الخاصية التكرارية الآمنة (idempotency) — غير قابلة للتفاوض#
كل استدعاء يغيّر حالة الدفع يحمل idempotency key يوفّره العميل، وكل webhook من الـ gateway يُتحقَّق من توقيعه ويُعالَج بشكل idempotent مرتبطًا بمعرّف الحدث لدى الـ gateway. البوابات تعيد المحاولة. المعالجة المكرّرة لعملية capture تعني خصمًا مزدوجًا، وهو في آن واحد حدث يمسّ ثقة العميل واسترداد نزاعي (chargeback).
C-02 — اشتراك مزوّد الخدمة#
SRC-BRD §7.1, §9.3.3 · SRC-MOM BR-3 · CON-07 (الخطط قابلة للتهيئة عبر Admin Panel)
حالة الاشتراك هي ما يتحكم في الظهور ضمن الدليل — وهذا هو العمود الفقري للإيرادات المتكررة للمنصة.
sequenceDiagram
autonumber
participant SP as 🚚 Service Provider
participant API as Qwizin API
participant PAY as 💳 PSP
participant SCH as Scheduler
participant IDX as Search Index
participant N as Notifications
rect rgb(240,240,255)
Note over SP,IDX: Initial subscription
SP->>API: GET /v1/subscription-plans
Note over API: Plans are ADMIN-CONFIGURABLE data,<br/>not code (CON-07).<br/>Monthly + annual tiers.
SP->>API: POST /v1/subscriptions {plan_id}
API->>API: ⚠ Precondition: account.state == active<br/>(documents approved — BR-RL-1)
API->>PAY: Create subscription / initial charge
PAY-->>API: Confirmed
API->>DB: subscription(state: active, period_end)
API->>IDX: 🔍 Index listing as VISIBLE
N->>SP: 🔔 Subscription active
end
rect rgb(255,245,235)
Note over SCH,IDX: Renewal cycle
SCH->>API: T-7d: upcoming renewal
N->>SP: 🔔 Renewal reminder
SCH->>PAY: Charge on period_end
alt Payment succeeds
PAY-->>API: Confirmed
API->>DB: period_end += interval
else Payment fails
API->>DB: subscription(state: past_due)
N->>SP: 🔔 Payment failed
loop Dunning: retry schedule
SCH->>PAY: Retry
end
alt Still failing after grace period
API->>DB: subscription(state: lapsed)
API->>IDX: 🔍 Remove listing from index
N->>SP: 🔔 Listing no longer visible
Note over API,IDX: ⚠ Grace period length UNDEFINED<br/>→ OQ-20
end
end
end
rect rgb(255,240,240)
Note over SP,IDX: Cancellation
SP->>API: DELETE /v1/subscriptions/{id}
API->>DB: cancel_at_period_end = true
Note over API: Access retained until period_end —<br/>they paid for it. Do NOT revoke immediately.
SCH->>API: At period_end
API->>IDX: 🔍 Remove from index
end
حالة الاشتراك تتحكم في الظهور ضمن الدليل#
stateDiagram-v2
[*] --> none: Provider approved,<br/>no subscription
none --> active: Payment succeeds
active --> past_due: Renewal fails
past_due --> active: Retry succeeds
past_due --> lapsed: Grace period exhausted
lapsed --> active: Provider resubscribes
active --> cancelling: Provider cancels
cancelling --> lapsed: period_end reached
note right of none
Visible in directory: ❌
end note
note right of active
Visible in directory: ✅
end note
note right of past_due
Visible: ✅ (grace)
— do not punish a
transient card failure
end note
note right of lapsed
Visible: ❌
end note
⚠️ يجب ألا يكون الـ index هو المرجع الموثوق هنا إطلاقًا. فهرس بحث قديم يعرض مزوّدًا منتهي الاشتراك على أنه نشط هو في الوقت نفسه مشكلة تجارية (ظهور غير مدفوع) ومشكلة ثقة (عملاء يتواصلون مع جهات غير نشطة). نتائج البحث تُرشَّح بعديًا مقابل قاعدة البيانات قبل إرجاعها (Flow 5).
C-03 — شراء الإدراج المميّز (featured)#
SRC-BRD §7.1, §9.3.4 · SRC-MOM REQ-06
flowchart LR
SP["🚚 Provider"] --> CHK{"Precondition:<br/>active subscription?"}
CHK -->|No| DENY["❌ Featured requires<br/>an active base subscription"]
CHK -->|Yes| PLANS["Featured packages<br/><i>admin-configurable</i><br/>duration · category · placement"]
PLANS --> PAY2["💳 Payment"]
PAY2 --> GRANT["featured_placement<br/>(category, starts_at, ends_at)"]
GRANT --> IDX2["🔍 Reindex with<br/>featured_rank + expiry"]
IDX2 --> RANK["→ C-04 ranking effect"]
SCH2["⏰ Scheduler"] -->|"at ends_at"| EXPIRE["Expire placement"]
EXPIRE --> IDX3["🔍 Reindex without boost"]
style DENY fill:#fde8e8,stroke:#c94a4a
style GRANT fill:#e8f5e9,stroke:#2d8659
سؤال المخزون الذي يثيره هذا التدفق: هل الإدراج المميّز غير محدود (كل من يدفع يحصل على تعزيز) أم نادر (N مقعدًا لكل فئة)؟
| النموذج | النتيجة |
|---|---|
| غير محدود | بسيط في البناء. لكن إذا كان كل مزوّد في فئة ما مميّزًا، فإن التعزيز يصبح بلا قيمة ويتدهور المنتج إلى رسوم مقابل لا شيء. |
| نادر (N لكل فئة) | يحافظ على القيمة ويدعم التسعير المميّز. يتطلب إدارة مخزون، وقائمة انتظار، ومعالجة التعارض عند لحظة الشراء. |
لم تتناوله أي وثيقة مصدر → OQ-21. التوصية: نادر، لأن التعزيز غير المحدود يلغي نفسه — لكن هذا قرار يخصّ نموذج العمل.
C-04 — أثر ترتيب الإدراج المميّز#
SRC-MOM REQ-06: "المزوّدون المشتركون في باقة Featured يظهرون في الأعلى"
هنا يتصادم الاهتمام التجاري مع جودة البحث، والخطأ في ذلك يدمّر الاثنين معًا.
flowchart TB
Q["🔍 Query: 'مورد أغذية' + filters"] --> NORM["Arabic normalisation<br/><i>alef · teh marbuta · yeh ·<br/>diacritics · tatweel</i>"]
NORM --> REL["Compute relevance score<br/>per candidate"]
REL --> BOOST["Apply featured multiplier"]
BOOST --> CHECK{"Boost model?"}
CHECK -->|"❌ Sort by featured DESC,<br/>then relevance"| BAD["Irrelevant featured providers<br/>appear above relevant ones.<br/><b>Users stop trusting search.</b><br/>Featured product loses value."]
CHECK -->|"✅ Relevance × bounded multiplier"| GOOD["Featured providers outrank<br/>comparable non-featured.<br/>An irrelevant result<br/><b>cannot</b> be promoted."]
GOOD --> DECAY["Apply recency decay<br/><i>stale featured listing must not<br/>outrank a perfect match forever</i>"]
DECAY --> HYD2["Hydrate from DB"]
HYD2 --> POST["⚠ Post-filter:<br/>approved AND subscription current"]
POST --> OUT["Ranked results<br/>+ featured badge"]
style BAD fill:#fde8e8,stroke:#c94a4a
style GOOD fill:#e8f5e9,stroke:#2d8659
style POST fill:#fff4e5,stroke:#d98c1f
قاعدة التصميم#
تعزيز featured هو مُضاعِف محدود يُطبَّق على درجة الملاءمة (relevance)، وليس تجاوزًا لها إطلاقًا. يجب ألا يظهر مورّد تغليف مميّز فوق مورّد أغذية ملائم حين يبحث المستخدم عن الأغذية. وفي اللحظة التي يتعلّم فيها المستخدمون أن النتائج الأولى مشتراة لا ملائمة، يتوقفون عن قراءتها — ويصبح منتج featured الذي اشتُريت به بلا قيمة.
⚠️ هذا يقيّد اختيار محرك البحث. أظهر البحث أن أحد المرشحين البارزين (Meilisearch) لا يدعم التعزيز وقت الاستعلام (query-time boosting) إطلاقًا — فالتعزيز فيه قاعدة ترتيب على مستوى الفهرس، وبسبب الفرز التجميعي (bucket sort) لا يفصل إلا بين المستندات المتساوية أصلًا في كل قاعدة سابقة. ورفعه في ترتيب القواعد يُضعف ملاءمة النص عالميًا، ولكل استعلام، لأنه إعداد وليس معاملًا. أما المحركات ذات التقييم التعبيري وقت الاستعلام فتلبّي هذا المتطلب أصلًا. انظر
R-11.
C-05 — التحويلات (payouts) للمستشارين والمزوّدين ⚠#
التدفق الأكثر تأثرًا بـ R-01.
sequenceDiagram
autonumber
participant SCH as ⏰ Scheduler
participant API as Qwizin API
participant PSP as 💳 SAMA-licensed PSP
participant CON as 🎓 Consultant
participant ADM as 🛡️ Admin
rect rgb(240,240,255)
Note over CON,PSP: Onboarding — Model B
CON->>API: Provide payout details
API->>PSP: Initiate sub-merchant onboarding
PSP->>CON: KYC / AML directly with PSP
Note over PSP,CON: ⚠ KYC is the PSP's obligation<br/>under ITS licence — not Qwizin's.<br/>This is the point of Model B.
PSP-->>API: {sub_merchant_ref, status}
API->>DB: Store reference ONLY — never bank details
end
rect rgb(240,255,240)
Note over SCH,PSP: Earnings & settlement
SCH->>API: Compute settlement period
API->>DB: Aggregate completed sessions + delivered requests
API->>API: Apply commission
API->>DB: statement(gross, commission, net) — immutable
API->>PSP: Instruct split settlement
PSP->>CON: 💰 Funds — direct, never via Qwizin
API->>DB: 📝 Hash-chained financial audit entry
end
rect rgb(255,240,240)
Note over CON,ADM: ⚠ Highest-value fraud target
CON->>API: Change payout bank details
API->>API: 🔐 Step-up MFA required
API->>API: ⏳ Delay window before effective
API->>CON: 🔔 Out-of-band notification to<br/>PREVIOUS contact channel
API->>DB: 📝 Audit with actor + IP
Note over API,CON: Account takeover → redirect payouts<br/>is the classic marketplace fraud.<br/>MFA + delay + out-of-band alert<br/>are all required, not optional.
end
الضوابط#
| الضابط | المبرر |
|---|---|
| عدم تخزين البيانات البنكية إطلاقًا — فقط مرجع الـ sub-merchant لدى الـ PSP | يزيل فئة كاملة من الاختراقات وعبء الامتثال |
| مصادقة مُعزَّزة (step-up) بـ MFA عند تغيير بيانات الـ payout | الهدف الأعلى قيمة للاحتيال في النظام بأكمله |
| نافذة تأخير + إشعار خارج النطاق (out-of-band) إلى القناة السابقة | يمنح المالك الشرعي فرصة للتدخل بعد الاستيلاء على الحساب |
| سجل تدقيق مسلسل بالتجزئة (hash-chained) لكل الأحداث المالية | خطر الإنكار — السجل العادي القابل للتعديل غير كافٍ حين يستطيع أي شخص لديه صلاحية الكتابة في قاعدة البيانات إعادة كتابة التاريخ |
| كشوف حساب غير قابلة للتعديل | التصحيحات قيود تسوية جديدة، لا تعديلات |
C-06 — الإدارة وسير عمل الاعتماد#
SRC-BRD §7.1 ("إدارة متعددة الأدوار") · SRC-UFC (Admin Portal)
flowchart TB
subgraph ROLES["⚠ Multi-role administration — CONF-03 unresolved"]
R1["Approval Reviewer<br/>documents, accounts"]
R2["Content Manager<br/>templates, learning, assessments"]
R3["Marketplace Manager<br/>consultants, providers, featured"]
R4["Finance<br/>payments, payouts, refunds"]
R5["Support<br/>read-mostly, impersonation"]
R6["Super Admin<br/>role assignment"]
end
subgraph GUARD["Admin access controls"]
G1["🔐 MFA mandatory"]
G2["Separate origin from<br/>user-facing app"]
G3["📝 EVERY action audited"]
G4["Impersonation explicitly<br/>logged + time-boxed"]
end
subgraph QUEUES["Work queues"]
Q1["📥 Document review<br/><i>oldest-first, SLA-tracked</i>"]
Q2["📥 Custom template requests"]
Q3["📥 Disputes / refunds"]
Q4["📥 Reported content"]
end
ROLES --> GUARD --> QUEUES
style R6 fill:#fde8e8,stroke:#c94a4a
style G1 fill:#fff4e5,stroke:#d98c1f
⚠️ تقسيم أدوار المسؤولين أعلاه مقترح، لا مواصفة. تقول
SRC-BRD§7.1 "إدارة متعددة الأدوار" دون تعداد الأدوار، ومصفوفة §11 غير متسقة داخليًا (CONF-03). لا يمكن بناء التخويل حتى تصدر مصفوفة مصحّحة (OQ-06).
لماذا المسؤول هو الهدف الأعلى قيمة#
يستطيع مسؤول المنصة اعتماد الحسابات، والاطلاع على الوثائق القانونية لكل مستأجر، ولمس المدفوعات. اختراق حساب مسؤول واحد يعادل اختراق المنصة بأكملها. ومن هنا: MFA إلزامي، وأصل (origin) منفصل، وتغطية تدقيق كاملة، وانتحال هوية المستخدم (impersonation) مسجَّل صراحةً ومحدود زمنيًا — فموظفو الدعم سيحتاجون إلى رؤية ما يراه المستخدم، ويجب أن تكون هذه القدرة قابلة للملاحظة لا خفيّة.
C-07 — إدارة المحتوى والـ marketplace#
flowchart LR
subgraph CM["Content management"]
T["Templates<br/>create · version · publish · retire"]
L["Learning modules<br/>author · publish"]
A["Assessments<br/>question banks · passing score ⚠"]
CAT["Categories & taxonomy<br/><i>bilingual</i>"]
end
subgraph MM["Marketplace management"]
CN["Consultants<br/>approve · suspend · verify specialties"]
PR["Providers<br/>approve · suspend · categories"]
FT["Featured inventory<br/><i>if scarce — OQ-21</i>"]
PL["Subscription plans<br/><i>CON-07: configurable</i>"]
end
CM --> PUB["Publish → versioned,<br/>previous version retained"]
MM --> IDX4["→ Reindex affected listings"]
A -.->|"⚠ CON-08"| SCORE["Passing score is<br/>ADMIN-CONFIGURABLE<br/>per assessment"]
style SCORE fill:#fff4e5,stroke:#d98c1f
قيدان من SRC-BRD §12 يجعلان هذه الأمور بيانات، لا كودًا:
CON-07— باقات الاشتراك قابلة للتهيئة عبر Admin PanelCON-08— درجة النجاح في التقييم قابلة للتهيئة من قِبل المسؤول
كلا القيدين يُستوفى ببساطة تامة إذا صُمّم كتهيئة (configuration) من البداية، ويتطلب تغييرًا في الكود ونشرًا لكل تعديل إذا كُتب بشكل صلب. تغيير درجة النجاح يجب ألا يستلزم إصدارًا إطلاقًا.
⚠️ سؤال الأثر الرجعي: إذا خفّض المسؤول درجة النجاح، فهل تنجح المحاولات الراسبة سابقًا بأثر رجعي؟ شبه مؤكد أن لا — لكن على النظام أن يقرّر ذلك صراحةً لا عرضًا. → OQ-22
C-08 — التقارير ولوحة المعلومات#
SRC-BRD §7.1 · SRC-MOM §13 (مؤشرات الأداء الأربعة)
flowchart TB
subgraph SOURCES["Event sources — Pipeline 1"]
E1["BookingConfirmed<br/>ConsultationCompleted"]
E2["TemplateDownloaded<br/>CustomRequestDelivered"]
E3["AssessmentPassed<br/>CertificateIssued"]
E4["SubscriptionActivated<br/>FeaturedPurchased<br/>PaymentCaptured"]
end
subgraph PROJ["Projection — Pipeline 4"]
OUT2["Outbox"] --> P["Projectors"]
P --> RM[("Reporting read model<br/><i>pre-aggregated</i>")]
end
subgraph KPI["SRC-MOM §13 KPIs"]
K1["📊 Consultations booked<br/>& completed / month"]
K2["📊 Templates downloaded<br/>& customised"]
K3["📊 % employees passing<br/>& certified"]
K4["📊 MRR — subscriptions<br/>+ featured packages"]
end
subgraph VIEWS["Dashboards"]
V1["🛡️ Platform admin<br/><i>all tenants</i>"]
V2["🏢 Company admin<br/><i>own employees only —<br/>RLS enforced</i>"]
V3["🎓 Consultant<br/><i>own bookings + earnings</i>"]
V4["🚚 Provider<br/><i>own listing performance</i>"]
end
E1 & E2 & E3 & E4 --> OUT2
RM --> K1 & K2 & K3 & K4
K1 & K2 & K3 & K4 --> V1
RM --> V2 & V3 & V4
style V2 fill:#fff4e5,stroke:#d98c1f
نقطتا تصميم#
مؤشرات الأداء الأربعة هي الحد الأدنى القابل للتطبيق من سطح التحليلات، ويجب تصميمها ضمن النظام منذ البداية. كل مؤشر منها يتطلب التقاط أحداث في module محدّد. وإعادة بناء "عدد القوالب المُنزَّلة" من سجلات الوصول بعد عام أغلى بكثير — وأقل دقة — من إصدار حدث (domain event) لحظة التنزيل.
⚠️ التقارير سطح خطر على عزل المستأجرين (tenant isolation). استعلامات التجميع هي بالضبط الموضع الذي يُغرى فيه المطوّر بتجاوز نطاق المستأجر "لأنه مجرد عدّ". ولوحة معلومات شركة تسرّب إحصاءات موظفي شركة أخرى هي الاختراق نفسه الذي يمثله تسريب سجلاتهم (
QAS-SEC-01). نموذج القراءة الخاص بالتقارير محصور بالمستأجر ومحمي بـ RLS تمامًا كالجداول المعاملاتية — بلا استثناءات للتجميعات.
C-09 — توزيع الإشعارات (fan-out)#
SRC-BRD §13 التبعيات 8/12/13 · SRC-MOM "Could Have" (تذكيرات المواعيد)
flowchart TB
subgraph TRIG["Triggers"]
T1["Account state changed"]
T2["Booking confirmed / declined /<br/>expired / reminder"]
T3["Document approved / rejected"]
T4["Certificate issued"]
T5["Training assigned / overdue"]
T6["Payment succeeded / failed"]
T7["Custom request delivered"]
end
TRIG --> EV["Domain event → Outbox"]
EV --> DISP["Notification dispatcher"]
DISP --> PREF{"User channel<br/>preferences<br/>+ locale"}
PREF --> EMAIL["✉️ Email"]
PREF --> SMS["📱 SMS ⚠"]
PREF --> PUSH["🔔 Push (APNs/FCM)"]
PREF --> INAPP["📥 In-app inbox"]
EMAIL & SMS & PUSH --> RETRY{"Delivered?"}
RETRY -->|No| BACKOFF["Exponential backoff<br/>retry queue"]
BACKOFF --> RETRY
RETRY -->|"Exhausted"| DLQ["Dead letter<br/>+ alert"]
RETRY -->|Yes| LOG2["📝 Delivery record"]
style SMS fill:#fff4e5,stroke:#d98c1f
style DLQ fill:#fde8e8,stroke:#c94a4a
قواعد التصميم#
| القاعدة | المبرر |
|---|---|
| لا تكون أبدًا في المسار المتزامن | تعطّل مزوّد الإشعارات يجب ألا يُفشل عملية حجز (QAS-AVL-04) |
| القوالب ثنائية اللغة، تُحسم من locale المستلِم | لا من locale المرسِل، ولا من locale التطبيق الحالي |
| صندوق الوارد داخل التطبيق هو القناة المعمّرة | البريد والـ SMS بذل أفضل جهد؛ السجل داخل التطبيق هو ما يجب أن يبقى |
| إزالة التكرار | مهام التذكير تعيد المحاولة؛ وتلقّي العميل خمس نسخ من تذكير واحد حدث يمسّ الثقة |
| ساعات هدوء للإشعارات غير العاجلة | مراعاة ساعات العمل في السعودية |
⚠️ الـ SMS مُعلَّم بإشارة تحذير. تتحفّظ SRC-BRD §13 التبعية 13 بعبارة "إن نُفِّذت"، لكن OTP متطلب صارم إذا شُحن التسجيل بالهاتف (F-01). وقد ظهر قيدان إضافيان في البحث: متطلبات تسجيل مُعرِّف المرسِل (sender ID) في السعودية لدى هيئة الاتصالات (غير مُتحقَّق منه — تحقّق قبل اختيار مزوّد)، واحتيال ضخّ الرسائل (SMS pumping)، وهو مسار خسارة مالية مباشرة يتطلب حصصًا لكل رقم هاتف، ولكل IP، ولكل دولة.
الأسئلة المفتوحة الجديدة المجمّعة#
| المعرّف | السؤال | التدفق | معيق |
|---|---|---|---|
OQ-20 |
ما طول فترة السماح في الاشتراك قبل إزالة الإدراج من الدليل؟ | C-02 | متوسط |
OQ-21 |
هل الإدراج المميّز غير محدود أم نادر (N لكل فئة)؟ | C-03 | نعم — نموذج العمل |
OQ-22 |
هل خفض درجة النجاح يُنجح المحاولات السابقة بأثر رجعي؟ | C-07 | متوسط |
OQ-23 |
نموذج نسبة العمولة — نسبة ثابتة، متدرّجة، أم حسب الفئة؟ | C-05 | نعم — يعيق تصميم التسوية المالية |
OQ-24 |
تواتر التسوية المالية — أسبوعي، شهري، عند الطلب؟ | C-05 | نعم |
OQ-25 |
من يتحمّل رسوم بوابة الدفع — المنصة، أم المستشار، أم العميل؟ | C-01, C-05 | نعم |
التتبعية — تغطية كاملة لـ BRD §7.1#
كل ميزة ضمن نطاق الـ MVP باتت الآن ذات تدفق موثّق.
| مجموعة BRD §7.1 | الميزات | مغطّاة بـ |
|---|---|---|
| إدارة المستخدمين | 9 ميزات | F-01, F-02, F-03, Flow 1 |
| التحقق من الحساب | 5 ميزات | Flow 2, F-04 |
| وحدة الاستشارات | 7 ميزات | F-05, F-06, Flow 3 |
| القوالب | 4 ميزات | F-07, F-08 |
| التدريب | 4 ميزات | F-09 |
| التقييمات | 4 ميزات | Flow 4 |
| الشهادات | 3 ميزات | Flow 4 |
| Marketplace | 4 ميزات | Flow 5, C-03, C-04 |
| الدفع | 4 ميزات | C-01, C-02, C-03, F-08 |
| الإدارة | 8 ميزات | C-06, C-07, C-08 |
| (ضمنية) | الإشعارات | C-09 |
| (ضمنية) | Payouts | C-05 |
الصفّان الأخيران جديران بالانتباه: الـ payouts والإشعارات لا تظهر إلا كتبعيات في
SRC-BRD§13، ولم تُدرج قط كميزات ضمن النطاق — ومع ذلك تحمل الـ payouts أكبر خطر تنظيمي في المشروع (R-01)، والإشعارات حاملة للأحمال في كل تدفق تقريبًا. كلاهما يحتاج تحديد نطاق صريح.