المعمارية English

arc42 §6b — تدفقات بيانات الميزات: المنصة الأساسية

الحالة: مسودة v0.1 · التاريخ: 2026-07-20 يغطي: SRC-BRD §7.1 — إدارة المستخدمين · التحقق من الحسابات · الاستشارات · القوالب · التدريب · التقييمات · إصدار الشهادات الوثيقة المرافقة: 06c-feature-flows-commerce-admin.md · 06-runtime-view.md


فهرس الميزات ← التدفقات#

كل ميزة من ميزات الـ MVP في SRC-BRD §7.1، مربوطة بالتدفق الذي يصفها.

ميزة BRD §7.1 Module التدفق الوثيقة
تسجيل الفرد / الشركة / المستشار / المزوّد MOD-IAM F-01 هذه
Google Sign-In · التسجيل بالبريد · التسجيل بالهاتف MOD-IAM Flow 1 06
إدارة الملف الشخصي MOD-IAM F-02 هذه
حسابات الموظفين MOD-IAM F-03 هذه
رفع المستندات القانونية · مراجعة المسؤول · اعتماد/رفض/إعادة تقديم MOD-ONB Flow 2 06
آلة حالات تفعيل الحساب MOD-ONB F-04 هذه
دليل المستشارين · الملفات التعريفية MOD-CONS F-05 هذه
حجز الاستشارة · اعتماد الموعد · الحالة MOD-CONS Flow 3 06
الاستشارة المرئية MOD-VID Flow 3 06
الاستشارة الميدانية (on-site) MOD-CONS F-06 هذه
القوالب التشغيلية المجانية · التنزيلات · تصفّح التصنيفات MOD-TPL F-07 هذه
طلبات القوالب المخصّصة MOD-TPL F-08 هذه
المحتوى التعليمي · تعلّم الموظفين · إسناد الشركة · التقدّم MOD-LRN F-09 هذه
اختبارات MCQ · التصحيح الآلي · درجة النجاح · السجل MOD-ASMT Flow 4 06
توليد الشهادات · التنزيل · السجل MOD-CERT Flow 4 06
دليل الموردين / المزوّدين · البحث · الترشيح MOD-MKT Flow 5 06
الإدراجات المميّزة (featured) MOD-MKT C-04 06c
كل تدفقات الدفع MOD-PAY C-01…C-05 06c
الإدارة · الاعتمادات · التقارير · لوحة المعلومات MOD-ADM C-06…C-08 06c
الإشعارات MOD-NOTIF C-09 06c

المستوى 0 — خريطة تدفق البيانات على مستوى النظام#

كيف تتحرك البيانات عبر مسارات معالجة (pipelines) المنصة. أربعة pipelines متمايزة بخصائص مختلفة في زمن الاستجابة والمتانة والأمن.

flowchart TB
    subgraph SRC["Data Sources"]
        U["👤 Users<br/>5 actor types"]
        ADM["🛡️ Admins"]
        EXT["🔌 External<br/>payment · video · SMS"]
    end

    subgraph P1["Pipeline 1 — Transactional (synchronous)"]
        direction LR
        API1["API"] --> VAL["Validate<br/>+ AuthZ<br/>+ Tenant scope"] --> TX[("PostgreSQL<br/>ACID")]
    end

    subgraph P2["Pipeline 2 — Document (async, untrusted)"]
        direction LR
        UP["Upload"] --> QUAR["Quarantine<br/>bucket"] --> SCAN["Malware<br/>scan"] --> PROM["Promote"] --> STORE[("Object Storage<br/>encrypted")]
    end

    subgraph P3["Pipeline 3 — Generation (async, burst)"]
        direction LR
        TRIG["Trigger"] --> JQ["Job queue"] --> REND["Render<br/>Arabic-capable"] --> ART[("Artifacts<br/>certificates · docs")]
    end

    subgraph P4["Pipeline 4 — Projection (async, eventually consistent)"]
        direction LR
        EVT["Domain<br/>events"] --> OUT["Outbox"] --> PROJ["Projectors"]
        PROJ --> IDX[("Search index")]
        PROJ --> RPT[("Reporting<br/>read model")]
        PROJ --> NOT["Notifications"]
    end

    U --> API1
    ADM --> API1
    EXT -->|"webhooks<br/>signature-verified<br/>idempotent"| API1
    U --> UP
    TX -.->|"emits"| EVT
    TX -.->|"triggers"| TRIG
    STORE -.-> REND
    ART --> STORE

    style P1 fill:#e8f0fe,stroke:#1168bd
    style P2 fill:#fde8e8,stroke:#c94a4a
    style P3 fill:#e8f5e9,stroke:#2d8659
    style P4 fill:#fff4e5,stroke:#d98c1f

التدفق: أربعة pipelines — معاملاتي متزامن، ومستندي لا متزامن للمدخلات غير الموثوقة، وتوليدي على دفعات، وإسقاطي (projection) متسق في النهاية يغذّي الفهرس والتقارير والإشعارات.

خصائص الـ Pipelines#

Pipeline زمن الاستجابة الاتساق سلوك الفشل الوضع الأمني
1 — معاملاتي p95 < 300 ms قوي (ACID) فشل سريع يظهر للمستخدم نطاق المستأجر وRLS يُفرضان هنا
2 — مستندي قبول < 1 ثانية، فحص p95 < 60 ثانية يظهر في النهاية الرفض عند الشك (fail closed) — لا ترقية لملف لم يُفحص أبدًا الأعلى — مدخلات غير موثوقة، bucket معزول
3 — توليدي p95 < دقيقتين متاح في النهاية إعادة محاولة؛ السجل المصدر محفوظ بمتانة سلفًا يُصيّر بيانات مستأجر — يجب إعادة تأسيس النطاق داخل المهمة
4 — إسقاطي ثوانٍ متسق في النهاية إعادة محاولة؛ ليس مرجعًا موثوقًا أبدًا الفهرس للترتيب فقط؛ قاعدة البيانات هي الحقيقة

القاعدة الحاكمة: يجوز أن تفشل الـ pipelines 2–4 دون فقدان عمل المستخدم، لأن الـ pipeline 1 قد أودع بالفعل وبشكل دائم السجلَّ الذي يهم. نتيجة التقييم تنجو من فشل توليد الـ PDF؛ والحجز ينجو من فشل الإشعار؛ والإدراج ينجو من فشل الفهرسة.


F-01 — التسجيل بحسب نوع الحساب#

SRC-BRD §7.1، §10 · SRC-MOM REQ-01 · SRC-UFC

أكثر تدفقات النظام تفرّعًا على الإطلاق. أربعة أنواع تُسجّل نفسها ذاتيًا ببيانات مطلوبة مختلفة ومسارات تفعيل مختلفة.

flowchart TB
    START["User opens app"] --> CHOOSE{"Select<br/>account type"}

    CHOOSE -->|Individual| I1["Collect: name, email/phone<br/>Optional: profession"]
    CHOOSE -->|Company| C1["Collect: company name, CR number,<br/>contact person, city, business type"]
    CHOOSE -->|Consultant| K1["Collect: name, specialties,<br/>credentials, bio"]
    CHOOSE -->|Service Provider| S1["Collect: company name, CR,<br/>service categories, coverage area"]

    I1 --> VERIFY["Verify identity channel<br/>OTP or Google ID token"]
    C1 --> VERIFY
    K1 --> VERIFY
    S1 --> VERIFY

    VERIFY --> CREATE["Create user + type-specific profile<br/><i>one transaction</i>"]

    CREATE --> GATE{"Approval<br/>required?<br/><i>CON-04</i>"}

    GATE -->|"Individual — No"| ACTIVE["✅ state: active<br/>Full access to<br/>individual capabilities"]
    GATE -->|"Company / Consultant /<br/>Provider — Yes"| PENDING["⏳ state: pending_documents"]

    PENDING --> DOCS["Prompt: upload legal documents<br/><i>→ Flow 2 in 06</i>"]
    DOCS --> REVIEW["state: under_review"]
    REVIEW --> DECIDE{"Admin<br/>decision"}
    DECIDE -->|Approved| ACTIVE2["✅ state: active"]
    DECIDE -->|Rejected| REJ["❌ state: rejected + reason"]
    REJ --> RESUB["Resubmission allowed<br/><i>new document version</i>"]
    RESUB --> REVIEW

    ACTIVE --> CAP["Capabilities resolved from<br/>actor type + account state"]
    ACTIVE2 --> CAP

    style PENDING fill:#fff4e5,stroke:#d98c1f
    style REJ fill:#fde8e8,stroke:#c94a4a
    style ACTIVE fill:#e8f5e9,stroke:#2d8659
    style ACTIVE2 fill:#e8f5e9,stroke:#2d8659

التدفق: الفرد يُفعَّل مباشرة؛ أما الشركة والمستشار والمزوّد فتمر بمسار مستندات ومراجعة إدارية، مع السماح بإعادة التقديم بعد الرفض.

البيانات المكتوبة#

المخزن البيانات
users الهوية، بيانات الاعتماد، مميّز actor_type، اللغة/المنطقة
{type}_profiles سمات خاصة بكل نوع — مملوكة للـ module المعني، لا مُلصَقة بـ users
account_state_transitions سجل تدقيق غير قابل للتغيير — الفاعل، من، إلى، السبب، الطابع الزمني

ملاحظة تصميمية (Design note). ستة أنواع فاعلين ليست ستة أدوار على جدول واحد. صف واحد في users يحمل الهوية وبيانات الاعتماد؛ وكل نوع فاعل يحصل على كيان ملف تعريفي مملوك لـ module الخاص به (Consultancy\ConsultantProfile، Directory\ProviderProfile). هذا يمنع MOD-IAM من أن يصير مكبًّا تمتد إليه كل الـ modules — وهو إخفاق Laravel الكلاسيكي حيث يراكم User علاقات من كل مكان فيصبح غير قابل للاستخراج (R-08).

أسئلة مفتوحة (Open questions)#

  • OQ-02 — مجموعة المستندات المطلوبة بدقة لكل نوع. غير معروف حاليًا هل تحتاج الشركة السجل التجاري فقط، أم أيضًا الرخصة البلدية وشهادة سلامة الغذاء. يعيق نموذج بيانات MOD-ONB.
  • OQ-12 — هل تُلتقط بيانات التسجيل بلغتين؟

F-02 — إدارة الملف الشخصي#

يبدو بسيطًا خادعًا؛ لكن التخويل هو المهم.

flowchart LR
    subgraph EDIT["Edit request"]
        REQ["PATCH /v1/profile"] --> AUTHZ{"Who is<br/>editing?"}
    end

    AUTHZ -->|"Self — Individual/Consultant/Provider"| FULL["Full profile fields<br/>editable"]
    AUTHZ -->|"Self — Employee"| LIMITED["⚠ LIMITED fields only<br/><i>BRD §11: 'Limited'</i><br/>name, phone, password, locale"]
    AUTHZ -->|"Company admin editing employee"| CO["Employment fields only<br/>NOT credentials"]
    AUTHZ -->|"Platform admin"| ADMIN["All fields<br/>📝 audit-logged"]

    FULL --> SENSITIVE{"Sensitive<br/>field?"}
    LIMITED --> SENSITIVE
    CO --> APPLY
    ADMIN --> APPLY

    SENSITIVE -->|"email / phone"| REVERIFY["Re-verify channel<br/>before applying"]
    SENSITIVE -->|"password"| REVOKE["Apply + revoke<br/>ALL token families"]
    SENSITIVE -->|"No"| APPLY["Apply change"]

    REVERIFY --> APPLY
    REVOKE --> APPLY
    APPLY --> REINDEX["Emit ProfileUpdated<br/>→ reindex if listing-visible"]

    style LIMITED fill:#fff4e5,stroke:#d98c1f
    style REVOKE fill:#fde8e8,stroke:#c94a4a

الضوابط:

  • تغيير قناة اتصال مُتحقَّق منها يجب أن يُعاد التحقق منه قبل أن تصير قناة الاسترداد — وإلا صار تعديل الملف الشخصي مسارًا للاستيلاء على الحساب.
  • تغيير كلمة المرور يُبطل كل الجلسات (QAS-SEC-04).
  • نطاق ملف الموظف ضيّق عن قصد بحسب SRC-BRD §11 — يجب ألا يستطيع الموظف تعديل سمات متعلقة بالتوظيف يعتمد عليها صاحب العمل.
  • ⚠️ تعديلات ملف المستشار/المزوّد التي تمسّ الظهور في الدليل أو التسعير ينبغي أن تعود إلى المراجعة إذا غيّرت جوهريًا ما جرى اعتماده. غير محدَّد في المصادر ← يُرفع إلى الجهة الراعية.

F-03 — تزويد حسابات الموظفين#

SRC-BRD §10.2، §10.3 · CON-09

الموظفون لا يستطيعون التسجيل ذاتيًا — فهم لا يوجدون إلا تحت شركة معتمدة.

sequenceDiagram
    autonumber
    participant CO as 🏢 Company Admin
    participant API as Qwizin API
    participant DB as PostgreSQL
    participant N as Notifications
    participant EMP as 👷 Employee

    CO->>API: POST /v1/company/employees {name, email/phone, job title}
    API->>API: AuthZ: is company_admin AND company.state == active
    Note over API: ⚠ CON-09: employee cannot exist<br/>under a non-approved company
    API->>DB: BEGIN TX
    API->>DB: Create user(actor_type: employee, state: invited)
    API->>DB: Link employment(company_id, employee_id, job_title)
    API->>DB: 📝 Audit: admin X created employee Y
    API->>DB: COMMIT
    API->>N: Dispatch invitation
    N->>EMP: 🔔 Invitation + one-time activation link

    EMP->>API: Activate {token, set password}
    API->>API: Validate token (single-use, expiring)
    API->>DB: user.state = active
    API-->>EMP: {access_token, refresh_token}

    rect rgb(255,240,240)
    Note over CO,EMP: ⚠ Cascade — OQ-07 UNRESOLVED
    CO->>API: Deactivate employee
    API->>DB: employment.state = terminated
    API->>DB: Revoke all token families
    Note over DB: Open: what happens to<br/>in-flight assessments?<br/>Already-issued certificates?<br/>→ OQ-07 needs a sponsor ruling
    end

مشكلة التتالي#

إيقاف الشركة أو رفضها يجب أن ينتشر إلى كل موظف. OQ-07 لا يزال دون حسم، لكن الآلية محسومة: تحديد سياق المستأجر يقع في مكان واحد، فتكون نقطة الانتشار واحدة لا متناثرة عبر الـ modules.

ثلاثة أسئلة فرعية تحتاج قرارًا:

السؤال الخيارات
محاولات التقييم الجارية إبطال / تجميد / السماح بالإكمال
الشهادات الصادرة سلفًا تبقى صالحة / تُوسَم كموقوفة / تُبطل
وصول الموظف الشخصي فقدان كل وصول / الاحتفاظ بالشهادات الشخصية فقط

نقطة نهاية التحقق من الشهادة تُعيد الحالة الحالية محسوبةً لحظيًا (QAS-INT-03)، فلا بد أن تملك جوابًا. هذا سؤال سياسة أعمال ذو أثر تقني ظاهر مباشرةً.


F-04 — آلة حالات تفعيل الحساب#

CON-04 · SRC-UFC · QAS-CMP-02

stateDiagram-v2
    [*] --> pending_documents: Registration complete<br/>(approval-gated types)
    [*] --> active: Registration complete<br/>(Individual)

    pending_documents --> under_review: All required documents<br/>uploaded + scanned clean
    under_review --> active: ✅ Admin approves ALL<br/>required documents
    under_review --> rejected: ❌ Admin rejects<br/>(reason required)
    rejected --> pending_documents: User resubmits<br/>(new document version)

    active --> suspended: Admin action /<br/>subscription lapse
    suspended --> active: Reinstated
    active --> closed: User or admin closes
    suspended --> closed: Escalation

    closed --> [*]

    note right of under_review
        Activation requires ALL required
        documents approved — not the first.
        Partial approval keeps the account
        in under_review.
    end note

    note right of rejected
        Resubmission creates document
        version n+1. NEVER overwrites n —
        the evidence behind the original
        decision must survive (QAS-CMP-02).
    end note

الأثر على التخويل#

«الحساب معتمد ونشط» هو شرط مسبق على الجلسة بكاملها، لا صلاحية. ونمذجته كصلاحية تعني أن كل نقطة نهاية جديدة تكون غير محمية افتراضيًا — وهو عكس المطلوب تمامًا في منصة قائمة على بوابة اعتماد.

يُنفَّذ بقائمة سماح صريحة: كل شيء مرفوض أثناء الانتظار، باستثناء قائمة قصيرة قابلة للمراجعة (عرض الملف الشخصي، رفع المستندات، إعادة التقديم، تصفّح الـ marketplace العام، تسجيل الخروج). وأي قدرة تُضاف العام القادم تكون مرفوضة افتراضيًا حتى يسمح بها أحدهم عن قصد.

⚠️ مزلق موثَّق في إطار العمل. التنفيذ البديهي — خطّاف before عام يُعيد false للحسابات غير المعتمدة — يُعطّل كل policy في التطبيق، لأن أي قيمة عائدة غير null تختصر التخويل كله. كما أنه يُعطّل قدرة المسؤول على مراجعة الحسابات المعلّقة. يجب أن يُعيد الخطّاف null في المسار السعيد، وأن تكون حالة الحساب في طبقة مخصّصة لتحديد القدرات لا في الخطّاف العام. واحجز الخطّاف العام لرفع صلاحية super-admin فقط.


F-05 — دليل المستشارين والملف التعريفي#

flowchart TB
    subgraph IDX["Indexing — async, Pipeline 4"]
        CE["Consultant approved /<br/>profile updated /<br/>availability changed"] --> DEB["Debounce"]
        DEB --> IX[("Search index<br/>name_ar · name_en · specialties ·<br/>city · price_band · rating · languages")]
    end

    subgraph BROWSE["Browse — Pipeline 1"]
        Q["GET /v1/consultants<br/>?specialty=&amp;city=&amp;type=&amp;q="] --> NORM["Normalise Arabic query"]
        NORM --> SR["Query index"]
        SR --> HYD["Hydrate from DB by ID"]
        HYD --> FILT["⚠ Post-filter:<br/>state == active<br/>AND approved"]
        FILT --> RES["Ranked results"]
    end

    subgraph PROFILE["Consultant detail"]
        RES --> DET["GET /v1/consultants/{id}"]
        DET --> PUB["Public: bio, specialties,<br/>credentials, pricing,<br/>consultation types offered"]
        DET --> AVAIL["Availability calendar<br/><i>⚠ OQ-03</i>"]
    end

    style FILT fill:#fde8e8,stroke:#c94a4a
    style AVAIL fill:#fff4e5,stroke:#d98c1f

OQ-03 — نموذج الإتاحة دون حسم. ثلاثة تصاميم مرشّحة تتباين تعقيدًا تباينًا ملموسًا:

النموذج جهد المستشار تعقيد النظام
إتاحة أسبوعية متكرّرة + استثناءات يُضبط مرة واحدة متوسط — توليد المواعيد، معالجة المناطق الزمنية
نشر مواعيد صريح مستمر منخفض
الطلب ثم التفاوض (بلا تقويم منشور) تفاعلي الأدنى، لكنه أسوأ تجربة استخدام ويتعارض مع تصميم انتهاء صلاحية الحجز في Flow 3

التوصية: الإتاحة المتكرّرة مع الاستثناءات. فهي تطابق طريقة عمل المهنيين فعليًا، كما أن قفل المواعيد في تدفق الحجز يفترض سلفًا وجود مواعيد منفصلة.


F-06 — طلب استشارة ميدانية (On-Site)#

SRC-BRD §7.1 · SRC-MOM FR-2

مختلف جوهريًا عن الاستشارة المرئية وغير قابل للتبادل معها — فهو ينطوي على سفر، وعنوان فعلي، وغياب أي إشارة إتمام يمكن للمنصة ملاحظتها.

sequenceDiagram
    autonumber
    participant C as 👤 Customer
    participant API as Qwizin API
    participant CON as 🎓 Consultant
    participant PAY as 💳 Payment
    participant N as Notifications

    C->>API: POST /v1/bookings {type: on_site, consultant, preferred dates[], site address, scope notes}
    API->>API: Validate: consultant offers on_site<br/>+ covers this city
    Note over API: ⚠ Coverage area is a<br/>consultant profile attribute —<br/>on-site is geographically bounded
    API->>DB: booking(type: on_site, state: pending_quote)

    rect rgb(255,245,235)
    Note over CON,PAY: Quotation — on-site pricing is not a fixed rate
    API->>CON: 🔔 On-site request + scope
    CON->>API: Provide quote {fee, travel cost, duration, date}
    API->>C: 🔔 Quote received
    alt Customer accepts
        C->>API: Accept quote
        API->>PAY: AUTHORIZE hold
        API->>DB: booking(state: confirmed)
    else Customer declines / no response
        API->>DB: booking(state: expired)
    end
    end

    rect rgb(240,255,240)
    Note over C,N: Visit & completion — NO automatic signal
    N->>C: 🔔 Reminder T-24h
    N->>CON: 🔔 Reminder T-24h
    Note over C,CON: Visit happens off-platform
    CON->>API: Mark visit completed + upload report
    C->>API: Confirm completion
    API->>PAY: CAPTURE
    Note over API,PAY: ⚠ Capture requires confirmation.<br/>Video sessions have provider webhooks;<br/>on-site has NOTHING — a human must<br/>assert it happened.
    end

    rect rgb(255,240,240)
    alt Dispute — customer says visit did not occur
        API->>API: Flag for admin resolution
        Note over API: ⚠ Policy undefined in all sources<br/>→ OQ-05
    end
    end

التدفق: الطلب يمر بمرحلة تسعير (quote) قبل الحجز على المبلغ، ثم تقع الزيارة خارج المنصة، ولا يقع التحصيل إلا بإقرار بشري من الطرفين.

لماذا يحتاج هذا التدفق تصميمًا منفصلًا#

الجانب الاستشارة المرئية الاستشارة الميدانية
التسعير سعر مستشار ثابت تسعير لكل طلب — سفر، نطاق، مدة
الجغرافيا غير ذات صلة منطقة التغطية تقيّد المطابقة
إشارة الإتمام webhook من المزوّد (SessionEnded) لا شيء — إقرار بشري فقط
مُطلِق التحصيل انتهاء الجلسة تأكيد الطرفين
دليل النزاع مدة الجلسة، أحداث الجودة تقرير المستشار المرفوع فقط

ذو دلالة معمارية: الاستشارات الميدانية بلا حقيقة يمكن للآلة ملاحظتها. كل انتقال حالة بعد التأكيد يعتمد على إقرار بشري، ومن ثمّ يحمل سجل التدقيق ومسار النزاع عبء النزاهة كاملًا. يعامل SRC-BRD نوعَي الاستشارة كميزة واحدة؛ وهما ليسا كذلك.


F-07 — كتالوج القوالب والتنزيل المجاني#

SRC-BRD §7.1 · SRC-MOM REQ-04 · BR-RL-2 (القوالب مجانية بالكامل لجميع أنواع الحسابات)

flowchart TB
    subgraph PUB["Publishing — admin, Pipeline 1+2"]
        A["🛡️ Admin uploads template"] --> META["Capture structured metadata:<br/>title_ar/en · category · subcategory ·<br/>description · file format · version"]
        META --> SCAN2["Malware scan"]
        SCAN2 --> STORE[("Object Storage<br/>templates/")]
        META --> DBT[("templates table")]
        DBT --> IXT["→ Search index"]
    end

    subgraph BR["Browse — Pipeline 1"]
        U["Any authenticated user<br/><i>all types — BR-RL-2</i>"] --> CAT["GET /v1/templates?category="]
        CAT --> LIST["Category tree + listings"]
        LIST --> DET2["GET /v1/templates/{id}"]
    end

    subgraph DL["Download"]
        DET2 --> DLREQ["POST /v1/templates/{id}/download"]
        DLREQ --> AUTHZ2["AuthZ: authenticated<br/><i>no payment gate</i>"]
        AUTHZ2 --> LOG["📊 Record download event<br/><i>KPI: templates downloaded</i>"]
        LOG --> SIGN["Issue signed URL, short TTL"]
        SIGN --> FETCH["Client fetches DIRECTLY<br/>from object storage"]
    end

    style FETCH fill:#e8f5e9,stroke:#2d8659

نقطتا تصميم أهم مما تبدوان:

  1. الملف لا يمرّ عبر طبقة الـ API إطلاقًا. نقل البيانات الضخمة عبر عمّال PHP-FPM يستهلك عاملًا طوال مدة كل تنزيل — وهو أسرع طريق لاستنزاف طبقة الطلبات. الحل: signed URL، وجلب مباشر، وCDN في المقدمة.
  2. أحداث التنزيل مؤشر أداء من الدرجة الأولى (SRC-MOM §13: "number of free templates downloaded and customised"). التقاطها لحظة التنزيل أمر تافه؛ أما إعادة بنائها لاحقًا من سجلات الوصول فليس كذلك.

SEAM-03 — نمذجة القوالب بشكل مُهيكل#

تتضمن ملفات العيّنة الستة في مجموعة المصادر (SRC-CNT) ثلاثة مصنّفات تدقيق هي قوائم فحص بصف لكل ضابط مع أعمدة لحالة الامتثال وللشخص المسؤول. وهذه البنية إشارة قوية إلى أن «ملف قابل للتنزيل» شكل انتقالي.

وعليه: تُنمذَج القوالب كيانات مُهيكلة بأقسام وعناصر مُصنّفة منذ اليوم الأول، وإن كان الـ MVP لا يقدّم سوى ملف. تكلفة الـ MVP هي مخطط بيانات أغنى خلف API لم يتغيّر؛ أما تكلفة التعديل اللاحق فهي إعادة نمذجة الـ module وترحيل كل سجل قائم (QAS-MOD-04).

erDiagram
    TEMPLATE ||--o{ TEMPLATE_SECTION : contains
    TEMPLATE_SECTION ||--o{ TEMPLATE_ITEM : contains
    TEMPLATE ||--o{ TEMPLATE_FILE : "has renditions"
    TEMPLATE {
        id id
        string title_ar
        string title_en
        string category
        int version
        enum kind "document | checklist | form"
    }
    TEMPLATE_SECTION {
        id id
        string title_ar
        string title_en
        int order
    }
    TEMPLATE_ITEM {
        id id
        text prompt_ar
        text prompt_en
        enum response_type "yes_no | na | text | numeric"
        bool required
    }
    TEMPLATE_FILE {
        id id
        string format "xlsx | pdf | docx"
        string storage_ref
    }

المرحلة الثانية تضيف جدول template_submissions فيوجد منتج التدقيق. ولا يتغيّر شيء في الـ MVP.


F-08 — طلب قالب مخصّص 💰#

SRC-BRD §7.1، §9.3.2 · SRC-MOM FR-3 / REQ-04 · CON-11 (أقل عدد ممكن من خطوات الواجهة — هاجس معدل الارتداد)

تدفق مُدرّ للإيرادات يتضمن خطوة تنفيذ بشرية.

sequenceDiagram
    autonumber
    participant U as 👤 Customer
    participant API as Qwizin API
    participant PAY as 💳 Payment
    participant ADM as 🛡️ Admin
    participant SPC as ✍️ Specialist
    participant OBJ as Object Storage
    participant N as Notifications

    rect rgb(240,240,255)
    Note over U,API: Intake — CON-11: MINIMAL steps
    U->>API: POST /v1/template-requests<br/>{base_template_id?, business_type, business_size,<br/>requirements_text, attachments?}
    Note over U,API: ⚠ Deliberately short form.<br/>Every extra field costs conversion<br/>on a paid action.
    API->>DB: request(state: submitted)
    API->>API: Determine price<br/><i>fixed / tiered / quoted</i>
    end

    rect rgb(255,245,235)
    Note over U,PAY: Payment
    alt Fixed or tiered price
        API-->>U: {price}
        U->>API: Pay {idempotency_key}
        API->>PAY: AUTHORIZE + CAPTURE
        Note over API,PAY: Capture immediately — unlike bookings,<br/>there is no counterparty acceptance step
        API->>DB: request(state: paid)
    else Quote required
        API->>ADM: 🔔 Quote needed
        ADM->>API: Provide quote
        API->>U: 🔔 Quote
        U->>API: Accept + pay
        API->>DB: request(state: paid)
    end
    end

    rect rgb(240,255,240)
    Note over ADM,OBJ: Fulfilment — HUMAN work, off-platform
    API->>ADM: 🔔 New paid request in queue
    ADM->>API: Assign to specialist
    API->>DB: request(state: in_progress, assignee, due_date)
    N->>U: 🔔 In progress, expected by {date}
    SPC->>API: Upload deliverable
    API->>API: Malware scan (Pipeline 2)
    API->>OBJ: Store → deliverables/
    API->>DB: request(state: delivered)
    N->>U: 🔔 Ready for download
    U->>API: Download via signed URL
    API->>DB: 📊 Record delivery acceptance
    end

    rect rgb(255,240,240)
    alt Revision requested
        U->>API: Request revision {notes}
        API->>DB: request(state: revision_requested)
        Note over API: ⚠ How many revisions are included?<br/>Undefined in all sources → OQ-14
    end
    end

التدفق: استمارة إدخال قصيرة عن قصد، ثم دفع يُحصَّل فورًا (بخلاف الحجوزات)، ثم تنفيذ بشري خارج المنصة ينتهي بتسليم عبر signed URL.

الواقع التشغيلي الذي يكشفه هذا التدفق#

هذه ليست ميزة مؤتمتة. إنها سير عمل لتقديم خدمة يتوسّطه إنسان، وله خصائص لا تتناولها الوثائق المصدر:

الفجوة لماذا تهم OQ جديد
SLA زمن الإنجاز العميل دفع وينتظر. ولا التزام تسليم مُعلَن. OQ-15
سياسة التعديلات تعديلات غير محدودة مقابل رسم ثابت التزام مفتوح بلا سقف OQ-14
طاقة التنفيذ الطلب غير محدود؛ وطاقة المتخصصين محدودة. يلزم مؤشر على عمق الطابور وربما تقييد الإدخال. OQ-16
الاسترداد عند عدم التسليم المال يُحصَّل مقدّمًا بلا ضمان تسليم مؤتمت OQ-05

النتيجة المعمارية: لأن التنفيذ يدوي، فإن مهمة النظام هي إدارة الطوابير وتتبّع الـ SLA والاحتفاظ بالأدلة — لا توليد المستندات. وتصميمه كميزة توليد سيكون خطأً في الفئة.


F-09 — إسناد التدريب وتتبّع تقدّم التعلّم#

SRC-BRD §7.1، §10.2 · SRC-TRN · ⚠️ خاضع لـ CONF-01

⚠️ تعارض في النطاق — يُقرأ قبل التنفيذ. يستبعد SRC-BRD §7.2 وSRC-MOM §14 التعلّم الإلكتروني بالفيديو، ومسارات التعلّم، وتحليلات التعلّم. بينما يحدّد SRC-TRN الفيديو كأسلوب تعلّم، ويضيف التقييمات العملية، ومقارنة الفروع، وتتبّع الدورات المتأخرة. والتدفق أدناه ينفّذ نطاق الـ BRD الأضيق. فإن كان SRC-TRN داخل النطاق، فسيتغيّر هذا التدفق تغيّرًا جوهريًا — إذ تصبح تخزين الفيديو، وتحويل الترميز (transcoding)، والـ CDN، ومسار تقييم يُصحَّح بشريًا، وهرمية شركة ← فرع، كلها مطلوبة.

flowchart TB
    subgraph AUTHOR["Content authoring — Admin"]
        A1["🛡️ Admin creates learning content"] --> A2["Structured: module → lessons<br/>title_ar/en · body_ar/en · order ·<br/>estimated_duration · category"]
        A2 --> A3["Link assessment<br/><i>MOD-ASMT</i>"]
        A3 --> A4["Publish → available to assign"]
    end

    subgraph ASSIGN["Assignment — Company Admin"]
        B1["🏢 Company admin selects content"] --> B2["Select employees<br/><i>individual / all / by job title</i>"]
        B2 --> B3["Set due date (optional)"]
        B3 --> B4["Create assignment records<br/><i>one per employee</i>"]
        B4 --> B5["🔔 Notify employees"]
    end

    subgraph LEARN["Learning — Employee"]
        C1["👷 Employee opens assigned module"] --> C2["Read lesson content"]
        C2 --> C3["Mark lesson complete"]
        C3 --> C4{"All lessons<br/>complete?"}
        C4 -->|No| C2
        C4 -->|Yes| C5["Unlock assessment"]
        C5 --> C6["→ Flow 4: MCQ assessment"]
    end

    subgraph TRACK["Progress — Company Admin"]
        D1["Progress events"] --> D2[("Progress read model<br/>Pipeline 4")]
        D2 --> D3["Company dashboard:<br/>assigned · started · completed ·<br/>passed · certificate issued"]
    end

    A4 --> B1
    B5 --> C1
    C3 -.->|"emits LessonCompleted"| D1
    C6 -.->|"emits AssessmentPassed"| D1

    style C6 fill:#e8f0fe,stroke:#1168bd

نموذج البيانات#

erDiagram
    LEARNING_MODULE ||--o{ LESSON : contains
    LEARNING_MODULE ||--o| ASSESSMENT : "gated by"
    LEARNING_MODULE ||--o{ ASSIGNMENT : "assigned via"
    ASSIGNMENT }o--|| EMPLOYEE : "to"
    ASSIGNMENT ||--o{ LESSON_PROGRESS : tracks
    ASSIGNMENT {
        id id
        id company_id "tenant scope"
        id employee_id
        id module_id
        date due_date
        enum state "assigned|in_progress|completed|overdue"
        timestamp assigned_at
    }
    LESSON_PROGRESS {
        id assignment_id
        id lesson_id
        timestamp completed_at
    }

ملاحظة على نطاق المستأجر: يحمل ASSIGNMENT عمود company_id ويخضع لـ RLS. أما محتوى التعلّم فهو عام على مستوى المنصة وغير مقيّد بنطاق المستأجر — والخطأ الشائع في النمذجة هو تقييد المحتوى بالشركات، وهو ما يمنع مشاركة المواد التي تؤلّفها المنصة.

تتبّع التقدّم إسقاط (projection) لا استعلام#

لوحات معلومات الشركات تقرأ من projection مبني في Pipeline 4، لا بتجميع الجداول المعاملاتية لحظيًا. فمؤشر SRC-MOM KPI 3 ("% of employees passing assessments and receiving certificates") هو شأن تقاريري، وحسابه من assignments ⋈ attempts ⋈ certificates عند كل تحميل للوحة سيتدهور مع نمو أعداد الموظفين.

SEAM-04 وSEAM-06#

  • SEAM-04MOD-LRN وMOD-ASMT وحدتان (modules) منفصلتان بينهما عقد، لأن نظام LMS الكامل هو أعلى القدرات المؤجلة صوتًا، وهو ينمو بسرعة إن نما أصلًا.
  • SEAM-06 — تُنمذَج أهداف الإسناد عبر مستوى من الوساطة (موظف، أو مجموعة موظفين) بدل تثبيت «الموظف فقط» في الكود. الأقسام مؤجلة (SRC-BRD §10.2) والفروع مُلمَّح إليها في SRC-TRN؛ وإقحام الهرمية لاحقًا في نموذج إسناد مسطّح مكلف.

أسئلة مفتوحة جديدة أثارها هذا التحليل#

ID السؤال التدفق يُعيق؟
OQ-14 كم عدد التعديلات المشمولة في طلب القالب المخصّص؟ F-08 نعم — التزام مفتوح بلا سقف
OQ-15 ما هو SLA التسليم للطلبات المخصّصة؟ F-08 نعم — العميل قد دفع
OQ-16 هل هناك حد لطاقة التنفيذ / تقييد للإدخال؟ F-08 متوسط
OQ-17 هل تعود تعديلات ملف المستشار المؤثرة على التسعير أو الظهور إلى المراجعة؟ F-02 متوسط
OQ-18 الاستشارات الميدانية: هل التسعير لكل طلب أم سعر مستشار ثابت؟ F-06 نعم — يعيق نموذج التسعير
OQ-19 من يتحمّل التكلفة عند وجود نزاع حول زيارة ميدانية؟ F-06 نعم — لا حقيقة يمكن للآلة ملاحظتها

تابع إلى: 06c-feature-flows-commerce-admin.md — المدفوعات، الاشتراكات، الإدراجات المميّزة، بوابة الإدارة، الإشعارات، التقارير.

القائد التقني · أمير هارون مسودة v0.1 · بحث وتصميم فقط