mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-17 23:09:35 +00:00
feat(paid-beta): operational layer for first 499 SAR — playbook + workflow + board + scorecard + landing CTA
Move from GO_PRIVATE_BETA (technical readiness) to PAID_BETA_READY (first revenue) — operational, not architectural. Deliverables: - docs/PAID_BETA_OPERATING_PLAYBOOK.md 10-section Arabic playbook: gate to Paid Beta, 7-day day-by-day plan (Staging → Outreach → Demos → Diagnostic → Pilot Sale → Pilot Day1/Day2 → Proof+Upsell), weekly targets (50-70 messages / 5-10 replies / 3-5 demos / 1+ payment), 8 hard operational rules, daily cadence, what NOT to add, Public Launch criteria. - docs/FIRST_PILOT_DELIVERY_WORKFLOW.md 48-hour Arabic Pilot delivery: T+0 intake (15 fields) → T+24 Free Diagnostic (3 opportunities + 1 Arabic message + 1 risk + 1 service recommendation) → T+48 Pilot 499 (10 opportunities + 7-day follow-up plan + Proof Pack) → T+7 final Proof Pack + 30min review + 3 upgrade paths. Pilot success criteria + 8-row metrics table. - docs/PRIVATE_BETA_OPERATING_BOARD.md 15-column Sheet template (company, person, segment, source, channel, message_sent, reply_status, demo_booked, diagnostic_sent, pilot_offered, price, paid, proof_pack_sent, next_step, notes) + status flow + ICP distribution + 3-wave follow-up templates + daily routine + PDPL privacy rules + CSV header. - landing/private-beta.html Pilot 499 SAR offer prominent at top (badge + hero CTA), dedicated 3-card pricing section (Pilot 499 / Free Diagnostic / Growth OS Monthly 2,999), 7-day refund/case-study guarantee, mailto CTAs with prefilled subject + body, removed duplicate pricing block. - scripts/paid_beta_daily_scorecard.py (274 lines) argparse with --messages, --replies, --demos, --pilots, --payments, --proof-packs, --as-of, --json. Computes reply_rate / demo_rate / pilot_rate / payment_rate, daily verdict (ON_TRACK / BEHIND / OFF_TRACK), weekly verdict (BLOCKERS / STRETCH_PENDING / WEEKLY_TARGETS_HIT), and rule-based next_actions in Arabic. Targets: 50-70 messages / 5-15 replies / 3-7 demos / 2-3 pilots / 1-2 paid / 1+ proof pack per week. - tests/unit/test_paid_beta_scorecard.py 12 tests: zero-input, on-track day, tone-action trigger, payment → proof-pack action, full-week target hit, conversion rates, Arabic text rendering, JSON validity, CLI text/json modes, --as-of today/explicit. Hard rules (unchanged): - No live WhatsApp / Gmail / Calendar send without env flag + approval. - No Moyasar API charge — manual invoice/payment-link only. - No LinkedIn scraping / auto-DM — Lead Gen Forms + manual outreach. - No cold WhatsApp without opt-in (PDPL hard-block). - Every message passes safety_eval + saudi_tone_eval. - Every action recorded in Action Ledger. Validation: - python -m compileall api auto_client_acquisition: clean. - pytest tests/unit (excl. tenacity-dep tests): 950 passed, 2 skipped. - python scripts/smoke_inprocess.py: SMOKE_INPROCESS_OK (8/8 endpoints). - python scripts/paid_beta_daily_scorecard.py text + --json: both render correctly with Arabic + verdict + next_actions. - tests/unit/test_positioning_lock.py: 10 passed (no prohibited phrases introduced in updated landing/private-beta.html). Test count: 949 → 962 (+12 new, 1 prior already counted). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
47f4dc2fb6
commit
342bcf8ea5
260
dealix/docs/FIRST_PILOT_DELIVERY_WORKFLOW.md
Normal file
260
dealix/docs/FIRST_PILOT_DELIVERY_WORKFLOW.md
Normal file
@ -0,0 +1,260 @@
|
||||
# First Pilot Delivery Workflow (48 ساعة)
|
||||
|
||||
> **القاعدة:** كل Pilot 499 ريال يُسلَّم خلال 48 ساعة. لا يتجاوز. لا live send. لا Moyasar API. لا scraping. كل خطوة approval-first.
|
||||
|
||||
---
|
||||
|
||||
## 1. الإطار العام
|
||||
|
||||
```
|
||||
T+0 intake (15 دقيقة)
|
||||
T+24 Free Diagnostic (3 فرص + رسالة + مخاطرة + توصية)
|
||||
T+48 Pilot Delivery (10 فرص + رسائل + متابعة + Proof Pack)
|
||||
T+7 Follow-up Wave (نتائج + اقتراح Growth OS أو case study)
|
||||
```
|
||||
|
||||
**الهدف الفعلي:** أن يقول العميل "هذا أفضل من شغل وكالتنا الحالية" خلال 48 ساعة.
|
||||
|
||||
---
|
||||
|
||||
## 2. T+0 — Intake (15 دقيقة)
|
||||
|
||||
### الحقول المطلوبة
|
||||
|
||||
```
|
||||
company_name مثال: "حلول الراحة للأثاث"
|
||||
sector construction | clinics | logistics | f&b | retail | edtech | software | other
|
||||
city الرياض / جدة / الدمام / الخبر / مكة / المدينة / الطائف
|
||||
ticket_size_sar 5_000 | 25_000 | 100_000 | 500_000+
|
||||
contact_name اسم صاحب القرار
|
||||
contact_role owner | gm | head_of_sales | head_of_marketing | other
|
||||
icp_today وصف العميل المثالي اليوم (3 أسطر)
|
||||
last_3_clients اسم القطاع + المدينة + حجم الصفقة (إن وُجد)
|
||||
channels_used whatsapp | gmail | linkedin_lead_forms | website_forms | calls
|
||||
data_in_hand crm | sheet | none
|
||||
why_now لماذا الآن؟ (3 أسطر — أول inbound dropped, slow Q, agency churn, ...)
|
||||
red_flags قطاعات/مناطق/أنواع لا يخدمها
|
||||
opt_in_status هل عنده WhatsApp opt-in موثق؟ نعم/لا
|
||||
```
|
||||
|
||||
### مصدر الـ intake
|
||||
- نموذج Google Form بسيط، أو
|
||||
- محادثة WhatsApp/Email مكتوبة (نسخها يدوياً).
|
||||
|
||||
### بعد الـ intake
|
||||
1. سجّل العميل في `PRIVATE_BETA_OPERATING_BOARD.md`.
|
||||
2. أنشئ مجلد `pilots/<slug>/` فيه: `intake.md`, `diagnostic.md`, `pilot.md`, `proof_pack.md`.
|
||||
3. أرسل تأكيد عربي:
|
||||
> وصلني intake. سأرسل لك Free Diagnostic خلال 24 ساعة. فيه 3 فرص محددة + رسالة جاهزة + مخاطرة موجودة + توصية. بدون أي إرسال خارجي بدون موافقتك.
|
||||
|
||||
---
|
||||
|
||||
## 3. T+24 — Free Diagnostic
|
||||
|
||||
### المحتوى المطلوب
|
||||
1. **3 فرص B2B محددة بأسماء حقيقية**
|
||||
- اسم الشركة + قطاعها + مدينتها + سبب الاهتمام (why_now).
|
||||
- كل فرصة لها صاحب قرار مرشح (اسم + دور).
|
||||
- كل فرصة لها قناة موصى بها (whatsapp opt-in / gmail / website_form / linkedin lead form / call).
|
||||
|
||||
2. **رسالة عربية جاهزة (تحت 80 كلمة)**
|
||||
- نبرة سعودية طبيعية (لا "تحية طيبة وبعد"، لا synergy).
|
||||
- تستخدم اسم العميل + قطاعه + سبب التواصل.
|
||||
- تنتهي بـ CTA واضح (مكالمة 12 دقيقة / لقاء قهوة / تجربة مجانية).
|
||||
- تمر `safety_eval` + `saudi_tone_eval` قبل التسليم.
|
||||
|
||||
3. **مخاطرة موجودة الآن**
|
||||
- تسريب data، WhatsApp بدون opt-in، إيميل bounce rate عالي، رسالة فيها claim طبي/مالي ممنوع.
|
||||
- مع توصية إصلاح من `incident_router` أو `support_sla`.
|
||||
|
||||
4. **توصية خدمة واحدة من Service Tower**
|
||||
- First 10 Opportunities Sprint (499) أو
|
||||
- Growth Diagnostic Pro (1,500) أو
|
||||
- Partnership Sprint (2,500) أو
|
||||
- Growth OS Monthly (2,999/شهر).
|
||||
|
||||
### Endpoints المستخدمة
|
||||
```
|
||||
POST /api/v1/customer-ops/onboarding/checklist
|
||||
POST /api/v1/service-excellence/review/all
|
||||
POST /api/v1/operator/bundles
|
||||
GET /api/v1/launch/private-beta/offer
|
||||
```
|
||||
|
||||
### قالب Diagnostic (عربي)
|
||||
|
||||
```
|
||||
Diagnostic — <company_name>
|
||||
|
||||
أهم 3 فرص لك هذا الأسبوع:
|
||||
1. <اسم الشركة 1> — <قطاع> — <مدينة>
|
||||
لماذا الآن: ...
|
||||
صاحب القرار: ...
|
||||
القناة: ...
|
||||
2. ...
|
||||
3. ...
|
||||
|
||||
رسالة عربية جاهزة (تحت 80 كلمة):
|
||||
"<الرسالة>"
|
||||
|
||||
مخاطرة موجودة الآن:
|
||||
- ...
|
||||
التوصية: ...
|
||||
|
||||
الخدمة الموصى بها:
|
||||
- First 10 Opportunities Sprint — 499 ريال — يبدأ غداً.
|
||||
- نسلّم: 10 فرص + 10 رسائل + خطة متابعة 7 أيام + Proof Pack.
|
||||
|
||||
— Bassam
|
||||
```
|
||||
|
||||
### بعد الإرسال
|
||||
- حدّث `Operating Board`: `diagnostic_sent = today`, `next_step = pilot_offer`.
|
||||
- تابع بعد 24 ساعة بقالب Follow-up #1.
|
||||
|
||||
---
|
||||
|
||||
## 4. T+48 — Pilot Delivery 499
|
||||
|
||||
### المحتوى المطلوب
|
||||
1. **10 فرص B2B**
|
||||
- كل فرصة فيها: company_name, sector, city, decision_maker, role, channel, why_now (3 أسطر), رسالة عربية جاهزة (تحت 80 كلمة), risk_score (0..100), contactability (1..5).
|
||||
|
||||
2. **خطة متابعة 7 أيام**
|
||||
- يوم 1: الرسالة الأولى.
|
||||
- يوم 3: رسالة متابعة #1 (لو ما رد).
|
||||
- يوم 5: رسالة متابعة #2 (تحويل قناة لو احتاج — مثلاً WhatsApp إلى Email).
|
||||
- يوم 7: قرار: keep / drop / nurture.
|
||||
|
||||
3. **Proof Pack مختصر**
|
||||
```
|
||||
opportunities_created: 10
|
||||
drafts_created: 10
|
||||
approvals_needed: 10
|
||||
risks_blocked: <count>
|
||||
recommended_next_action: <Growth OS Monthly | Partnership Sprint | Growth Diagnostic Pro>
|
||||
upgrade_offer: "نواصل شهرياً مقابل 2,999 ريال — أول شهر بسعر 1,999."
|
||||
```
|
||||
|
||||
### Endpoints المستخدمة
|
||||
```
|
||||
POST /api/v1/operator/chat/message
|
||||
POST /api/v1/customer-ops/connectors/summary
|
||||
POST /api/v1/revenue-launch/payment/invoice-instructions
|
||||
POST /api/v1/revenue-launch/proof-pack/template
|
||||
GET /api/v1/service-excellence/review/all
|
||||
```
|
||||
|
||||
### قالب Pilot Delivery (عربي مختصر)
|
||||
|
||||
```
|
||||
First 10 Opportunities Sprint — <company_name>
|
||||
|
||||
10 فرص أولى لك:
|
||||
1. ... | ... | ... | "<رسالة جاهزة>"
|
||||
2. ...
|
||||
...
|
||||
10. ...
|
||||
|
||||
خطة متابعة 7 أيام:
|
||||
- يوم 1: إرسال أول دفعة (5 رسائل) بعد اعتمادك.
|
||||
- يوم 3: متابعة الرسائل بدون رد.
|
||||
- يوم 5: تحويل قناة لمن لم يرد (Email → WhatsApp opt-in).
|
||||
- يوم 7: قرار keep/drop/nurture.
|
||||
|
||||
Proof Pack:
|
||||
- opportunities_created: 10
|
||||
- drafts_created: 10
|
||||
- approvals_needed: 10 (تنتظر اعتمادك)
|
||||
- risks_blocked: <count>
|
||||
|
||||
التوصية بعد 7 أيام:
|
||||
- Growth OS Monthly (2,999 ر.س/شهر) — نواصل من حيث وقفنا.
|
||||
- أو Case Study مجاني مقابل اقتباس.
|
||||
|
||||
— Bassam
|
||||
```
|
||||
|
||||
### بعد الإرسال
|
||||
- حدّث Operating Board: `pilot_offered = today`, `price = 499`, `paid = pending`.
|
||||
- أرسل Moyasar invoice manual (URL يدوي).
|
||||
- تابع تأكيد الدفع.
|
||||
|
||||
---
|
||||
|
||||
## 5. T+7 — Follow-up Wave + Proof Pack النهائي
|
||||
|
||||
### المحتوى
|
||||
1. **Proof Pack نهائي**
|
||||
- leads_count + drafts_approved + replies + meetings_booked + pipeline_sar + risks_blocked.
|
||||
- chart مبسط: messages_sent vs replies vs meetings.
|
||||
- أهم 3 رسائل اعتمدها العميل (مع التعديلات إن وُجدت).
|
||||
- أهم 3 مخاطر تم منعها تلقائياً.
|
||||
|
||||
2. **جلسة مراجعة 30 دقيقة**
|
||||
- "ما الذي اشتغل؟ ما الذي لم يشتغل؟"
|
||||
- "نواصل شهرياً، ولا نوقف، ولا نحوّل لـ case study؟"
|
||||
|
||||
3. **3 مسارات للترقية**
|
||||
- **Growth OS Monthly** (2,999 ر.س/شهر) — استمرار شهري.
|
||||
- **Partnership Sprint** (2,500 ر.س لمرة) — لو فيه شراكات قابلة.
|
||||
- **Case Study + Referral** — مقابل اسم وكالة/عميل آخر يحتاج Pilot.
|
||||
|
||||
### Endpoints المستخدمة
|
||||
```
|
||||
POST /api/v1/customer-ops/cs/weekly-check-in
|
||||
POST /api/v1/customer-ops/cs/success-plan
|
||||
POST /api/v1/revenue-launch/proof-pack/template
|
||||
GET /api/v1/service-excellence/review/all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. ما لا يحدث في Pilot Delivery
|
||||
|
||||
- لا live WhatsApp send بدون env flag + اعتماد.
|
||||
- لا live Gmail send بدون env flag + اعتماد.
|
||||
- لا Moyasar charge من API — invoice/payment-link manual فقط.
|
||||
- لا scraping LinkedIn — Lead Gen Forms + استرشادي فقط.
|
||||
- لا cold WhatsApp بدون opt-in — PDPL hard-block.
|
||||
- لا تجاوز 48 ساعة — لو فيه عذر، نعتذر بدل أن نتأخر.
|
||||
- لا تخفيض السعر بدون موافقة المؤسس — 499 ثابت.
|
||||
- لا توسيع scope في الـ Pilot — 10 فرص فقط، الزيادة في Growth OS.
|
||||
|
||||
---
|
||||
|
||||
## 7. شروط نجاح Pilot
|
||||
|
||||
- [ ] Diagnostic سُلّم خلال 24 ساعة.
|
||||
- [ ] Pilot سُلّم خلال 48 ساعة.
|
||||
- [ ] العميل اعتمد ≥3 رسائل من العشرة.
|
||||
- [ ] Proof Pack وصل خلال 7 أيام.
|
||||
- [ ] جلسة مراجعة 30 دقيقة تمت.
|
||||
- [ ] 1+ case study أو 1+ Growth OS subscription.
|
||||
- [ ] CSAT ≥ 8/10.
|
||||
|
||||
---
|
||||
|
||||
## 8. مقاييس Pilot في Operating Board
|
||||
|
||||
| Metric | Target |
|
||||
|--------|-------:|
|
||||
| Pilot delivered ≤ 48h | 100% |
|
||||
| Drafts approved (من 10) | ≥3 |
|
||||
| Replies received | ≥1 |
|
||||
| Meetings booked | ≥1 |
|
||||
| Risks blocked | ≥1 |
|
||||
| Upsell offered | 100% |
|
||||
| Upsell accepted | ≥30% |
|
||||
| CSAT | ≥8/10 |
|
||||
|
||||
---
|
||||
|
||||
## 9. القرار النهائي
|
||||
|
||||
```
|
||||
Pilot ليس "محاولة بيع".
|
||||
Pilot هو "أول إثبات أن Dealix يعمل لشركتك".
|
||||
لو سُلّم في 48 ساعة + ≥3 رسائل اعتمدت + 1 رد + 1 اجتماع =
|
||||
هذا Growth OS subscription بأعلى احتمال.
|
||||
```
|
||||
206
dealix/docs/PAID_BETA_OPERATING_PLAYBOOK.md
Normal file
206
dealix/docs/PAID_BETA_OPERATING_PLAYBOOK.md
Normal file
@ -0,0 +1,206 @@
|
||||
# Paid Beta Operating Playbook
|
||||
|
||||
> **القاعدة:** الجاهزية التقنية لا تعني دخل. هذا الـ playbook يحوّل GO_PRIVATE_BETA إلى أول 499 ريال خلال 7 أيام.
|
||||
|
||||
---
|
||||
|
||||
## 1. الحالة الحالية
|
||||
|
||||
```
|
||||
✅ Tests: 949 passed, 2 skipped
|
||||
✅ CI green
|
||||
✅ Service Tower + Service Excellence + Targeting OS + Customer Ops جاهزة
|
||||
✅ Positioning Lock مفعّل
|
||||
✅ Landing pages متوافقة مع POSITIONING_LOCK
|
||||
🟡 Staging: ينتظر النشر الفعلي
|
||||
🟡 First payment: ينتظر أول عميل
|
||||
```
|
||||
|
||||
**الحالة:** `GO_PRIVATE_BETA` محلياً. الانتقال لـ `PAID_BETA_READY` يحتاج Staging شغّال + أول Pilot مدفوع.
|
||||
|
||||
---
|
||||
|
||||
## 2. الانتقال من Private Beta إلى Paid Beta
|
||||
|
||||
### Gate الانتقال (لا تتجاوزه)
|
||||
|
||||
```text
|
||||
✅ Staging /health = 200
|
||||
✅ Service catalog يعرض 4+ خدمات
|
||||
✅ landing/private-beta.html فيه 499 SAR + CTA
|
||||
✅ no_secrets scan نظيف
|
||||
✅ live_sends_disabled = true
|
||||
✅ Moyasar invoice/payment-link manual flow جاهز
|
||||
✅ أول 20 prospect معرّفون في Operating Board
|
||||
```
|
||||
|
||||
### Smoke Commands
|
||||
|
||||
```bash
|
||||
export STAGING_BASE_URL="https://YOUR-STAGING-URL"
|
||||
python scripts/smoke_staging.py --base-url "$STAGING_BASE_URL"
|
||||
python scripts/launch_readiness_check.py --staging-url "$STAGING_BASE_URL"
|
||||
python scripts/paid_beta_daily_scorecard.py --as-of today
|
||||
```
|
||||
|
||||
المطلوب: `PAID_BETA_READY`. لو NO-GO → أصلح السبب قبل أي بيع.
|
||||
|
||||
---
|
||||
|
||||
## 3. خطة 7 أيام للوصول للدخل الأول
|
||||
|
||||
### يوم 1 — Staging + Outreach
|
||||
- نشر staging على Railway.
|
||||
- تشغيل smoke + readiness checks.
|
||||
- إرسال 10 رسائل (5 وكالات + 5 شركات).
|
||||
- 1 منشور LinkedIn (founder voice).
|
||||
|
||||
**الهدف:** 2 ردود + 1 ديمو محجوز.
|
||||
|
||||
### يوم 2 — Demos
|
||||
- إرسال 10 رسائل أخرى.
|
||||
- إجراء أول 1-2 ديمو.
|
||||
- بدء أول Free Diagnostic لأي عميل اهتم.
|
||||
|
||||
**الهدف:** 1 Free Diagnostic موعود.
|
||||
|
||||
### يوم 3 — Diagnostic Delivery
|
||||
- تسليم أول Free Diagnostic خلال 24 ساعة.
|
||||
- 5 follow-ups.
|
||||
- إرسال 5 رسائل جديدة.
|
||||
|
||||
**الهدف:** 1 Pilot Offer.
|
||||
|
||||
### يوم 4 — First Pilot Sale
|
||||
- محادثة Pilot 499 مع المهتم.
|
||||
- إنشاء Moyasar invoice manual.
|
||||
- إرسال payment-link-message.
|
||||
|
||||
**الهدف:** 1 invoice paid أو commitment مكتوب.
|
||||
|
||||
### يوم 5 — Pilot Delivery Day 1
|
||||
- استلام intake من العميل.
|
||||
- تشغيل First 10 Opportunities Sprint workflow.
|
||||
- 10 opportunities + 10 رسائل عربية.
|
||||
|
||||
**الهدف:** Approval Pack مرسل للعميل.
|
||||
|
||||
### يوم 6 — Pilot Delivery Day 2
|
||||
- متابعة الموافقات.
|
||||
- تشغيل follow-up sequence.
|
||||
- أول 1-2 رد إيجابي.
|
||||
|
||||
**الهدف:** اعتماد ≥3 رسائل + Proof Pack v1.
|
||||
|
||||
### يوم 7 — Proof + Upsell
|
||||
- تسليم Proof Pack.
|
||||
- جلسة مراجعة 30 دقيقة.
|
||||
- اقتراح ترقية لـ Growth OS Pilot.
|
||||
|
||||
**الهدف:** Case study أو Pilot ثانٍ.
|
||||
|
||||
---
|
||||
|
||||
## 4. أهداف الأسبوع
|
||||
|
||||
| Metric | Target |
|
||||
|--------|-------:|
|
||||
| Messages sent | 50–70 |
|
||||
| Positive replies | 5–10 |
|
||||
| Demos booked | 3–5 |
|
||||
| Pilots offered | 2–3 |
|
||||
| Payments requested | 1–2 |
|
||||
| Payments received | 1+ |
|
||||
| Proof packs delivered | 1+ |
|
||||
|
||||
---
|
||||
|
||||
## 5. القواعد التشغيلية اليومية (لا تتنازل عنها)
|
||||
|
||||
1. **لا live WhatsApp send** بدون env flag + اعتماد بشري.
|
||||
2. **لا live Gmail send** بدون env flag + اعتماد بشري.
|
||||
3. **لا Calendar insert** بدون اعتماد.
|
||||
4. **لا Moyasar charge** من API — invoice/payment-link manual فقط.
|
||||
5. **لا scraping LinkedIn** ولا auto-DM — Lead Gen Forms + manual فقط.
|
||||
6. **لا cold WhatsApp** بدون opt-in — PDPL hard-block.
|
||||
7. **كل رسالة** تمر `safety_eval` + `saudi_tone_eval` قبل الإرسال.
|
||||
8. **كل فعل** يُسجّل في Action Ledger.
|
||||
|
||||
---
|
||||
|
||||
## 6. Daily Cadence
|
||||
|
||||
### الصباح (60 دقيقة)
|
||||
- شغّل `paid_beta_daily_scorecard.py`.
|
||||
- راجع الـ Operating Board.
|
||||
- اعتمد drafts اليوم (10–15 دقيقة).
|
||||
- 5 follow-ups.
|
||||
|
||||
### الظهر (90 دقيقة)
|
||||
- 1–2 ديمو.
|
||||
- 10 رسائل جديدة (segments متنوعة).
|
||||
|
||||
### العصر (60 دقيقة)
|
||||
- تسليم deliverable لعميل واحد.
|
||||
- إجابة support tickets (إن وجد).
|
||||
|
||||
### آخر اليوم (30 دقيقة)
|
||||
- تحديث Operating Board.
|
||||
- تشغيل scorecard مرة أخرى.
|
||||
- خطة الغد.
|
||||
|
||||
---
|
||||
|
||||
## 7. ما لا تضيفه هذا الأسبوع
|
||||
|
||||
- لا ميزات تقنية جديدة.
|
||||
- لا layers معمارية.
|
||||
- لا modules جديدة.
|
||||
- لا بريق landing.
|
||||
|
||||
**التركيز كله:** عميل واحد يدفع 499 ريال.
|
||||
|
||||
---
|
||||
|
||||
## 8. شروط الانتقال إلى Public Launch
|
||||
|
||||
لا انتقال قبل:
|
||||
```
|
||||
5–10 pilots
|
||||
2+ paid customers
|
||||
0 unsafe sends
|
||||
weekly proof packs delivered
|
||||
support flow يعمل
|
||||
funnel واضح من lead → demo → pilot → paid
|
||||
14 يوم staging stable
|
||||
billing live (Moyasar API webhook)
|
||||
terms + privacy + DPA
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Endpoints المهمة في Paid Beta
|
||||
|
||||
```
|
||||
GET /api/v1/launch/private-beta/offer
|
||||
POST /api/v1/launch/go-no-go
|
||||
GET /api/v1/launch/scorecard/demo
|
||||
GET /api/v1/operator/bundles
|
||||
POST /api/v1/operator/chat/message
|
||||
POST /api/v1/customer-ops/onboarding/checklist
|
||||
POST /api/v1/customer-ops/connectors/summary
|
||||
POST /api/v1/revenue-launch/payment/invoice-instructions
|
||||
POST /api/v1/revenue-launch/proof-pack/template
|
||||
GET /api/v1/service-excellence/review/all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. القرار النهائي
|
||||
|
||||
```
|
||||
لا تنتظر "كمال المنتج". المنتج كامل تقنياً.
|
||||
أنت تنتظر "أول إيراد".
|
||||
الإيراد يأتي من 50 رسالة يدوية + 5 ديمو + 1 invoice.
|
||||
ابدأ.
|
||||
```
|
||||
183
dealix/docs/PRIVATE_BETA_OPERATING_BOARD.md
Normal file
183
dealix/docs/PRIVATE_BETA_OPERATING_BOARD.md
Normal file
@ -0,0 +1,183 @@
|
||||
# Private Beta Operating Board
|
||||
|
||||
> **القاعدة:** كل prospect يدخل هذا الـ Board. كل خطوة تُسجّل. كل تأخير يولّد action item. هذا هو الـ source of truth للأسبوع.
|
||||
|
||||
---
|
||||
|
||||
## 1. أين يعيش هذا الـ Board؟
|
||||
|
||||
- **Primary:** Google Sheet خاص بك (لا تشاركه بصلاحيات edit مع أحد).
|
||||
- **Backup:** نسخة في `pilots/operating_board.csv` (gitignored) في المستودع.
|
||||
- **عدم التشارك:** هذا Sheet يحتوي PII لأشخاص لم يوافقوا — لا تشاركه.
|
||||
|
||||
---
|
||||
|
||||
## 2. الأعمدة (15 عمود)
|
||||
|
||||
| # | Column | النوع | شرح | مثال |
|
||||
|---|--------|------|------|------|
|
||||
| 1 | `company` | text | اسم الشركة الرسمي | شركة الأثاث المتقدم |
|
||||
| 2 | `person` | text | اسم صاحب القرار | أحمد العتيبي |
|
||||
| 3 | `segment` | enum | `agency` / `b2b_company` / `partnership` | b2b_company |
|
||||
| 4 | `source` | enum | `linkedin_lead_form` / `referral` / `inbound` / `event` / `personal_network` | personal_network |
|
||||
| 5 | `channel` | enum | `whatsapp` (opt-in) / `email` / `linkedin_dm_manual` / `call` | linkedin_dm_manual |
|
||||
| 6 | `message_sent` | date | تاريخ إرسال أول رسالة | 2026-05-01 |
|
||||
| 7 | `reply_status` | enum | `none` / `positive` / `objection` / `not_now` / `bounce` | positive |
|
||||
| 8 | `demo_booked` | date \| null | تاريخ الديمو لو حُجز | 2026-05-03 |
|
||||
| 9 | `diagnostic_sent` | date \| null | تاريخ تسليم Free Diagnostic | 2026-05-04 |
|
||||
| 10 | `pilot_offered` | date \| null | تاريخ عرض Pilot 499 | 2026-05-05 |
|
||||
| 11 | `price` | int | السعر المعروض (499 / 1500 / 2999) | 499 |
|
||||
| 12 | `paid` | enum | `no` / `pending_invoice` / `paid` / `case_study` | pending_invoice |
|
||||
| 13 | `proof_pack_sent` | date \| null | تاريخ تسليم Proof Pack | null |
|
||||
| 14 | `next_step` | text | الإجراء التالي وتاريخه | 2026-05-06: follow-up #1 |
|
||||
| 15 | `notes` | text | ملاحظات (بدون PII حساسة) | اهتم بـ partnerships في الرياض |
|
||||
|
||||
---
|
||||
|
||||
## 3. Status Flow
|
||||
|
||||
```
|
||||
prospect_added
|
||||
→ message_sent
|
||||
→ reply_status (none | positive | objection | not_now | bounce)
|
||||
→ demo_booked
|
||||
→ diagnostic_sent (T+24)
|
||||
→ pilot_offered (T+48)
|
||||
→ paid (or case_study)
|
||||
→ proof_pack_sent (T+7 من بدء Pilot)
|
||||
→ renewal_or_upsell
|
||||
```
|
||||
|
||||
كل عميل يجب أن يكون في حالة واحدة من هذه المراحل في كل لحظة.
|
||||
|
||||
---
|
||||
|
||||
## 4. أهداف الأسبوع (الصف الأول من الـ Board)
|
||||
|
||||
| Metric | Target | Tracking |
|
||||
|--------|-------:|----------|
|
||||
| Prospects added | 50–70 | عداد عمود `company` |
|
||||
| Messages sent | 50–70 | عدد التواريخ في `message_sent` |
|
||||
| Positive replies | 5–10 | `reply_status = positive` |
|
||||
| Demos booked | 3–5 | عدد التواريخ في `demo_booked` |
|
||||
| Diagnostics sent | 2–4 | عدد التواريخ في `diagnostic_sent` |
|
||||
| Pilots offered | 2–3 | عدد التواريخ في `pilot_offered` |
|
||||
| Paid | 1+ | `paid = paid` |
|
||||
| Proof packs sent | 1+ | عدد التواريخ في `proof_pack_sent` |
|
||||
|
||||
---
|
||||
|
||||
## 5. ICP Distribution (في 50–70 prospect)
|
||||
|
||||
```
|
||||
Agencies (B2B marketing agencies) 20%
|
||||
Construction & home services 20%
|
||||
Clinics + dental + aesthetic 15%
|
||||
Logistics + last-mile 15%
|
||||
F&B (restaurants + cloud kitchens) 10%
|
||||
Retail (offline + ecom) 10%
|
||||
EdTech / SaaS B2B 10%
|
||||
```
|
||||
|
||||
اضبط النسبة حسب القطاعات التي يخدمها العميل المثالي.
|
||||
|
||||
---
|
||||
|
||||
## 6. Cadence لكل prospect
|
||||
|
||||
| اليوم | الإجراء |
|
||||
|------|--------|
|
||||
| Day 0 | إرسال الرسالة الأولى + تسجيلها في الـ Board |
|
||||
| Day 1 | تحقق من reply_status + Operating Board update |
|
||||
| Day 2 | متابعة #1 (لو لا رد) — قالب Follow-up #1 |
|
||||
| Day 4 | متابعة #2 (لو لا رد) — تحويل قناة لو منطقي |
|
||||
| Day 7 | قرار keep / drop / nurture |
|
||||
| Day 14 | nurture: رسالة قيمة (مثل Diagnostic مجاني للناس البطيئين) |
|
||||
|
||||
---
|
||||
|
||||
## 7. Follow-up Templates (3 موجات)
|
||||
|
||||
### Follow-up #1 (يوم 2)
|
||||
> أنت اللي ذكرت <signal من الرسالة الأولى>. حضّرت لك مثال محدد لشركتك (3 فرص + رسالة جاهزة بالعربي + مخاطرة موجودة الآن). أرسله لك بعد ردك. ما يأخذ منك ≥3 دقائق.
|
||||
|
||||
### Follow-up #2 (يوم 4 — تحويل قناة لو منطقي)
|
||||
> سمعت أن <event حقيقي للقطاع>. هذا أفضل وقت تجرب نموذج بسيط: 10 فرص + رسائل خلال 48 ساعة، 499 ريال، يبدأ غداً. لو ما عجبك في 7 أيام، تستردّ المبلغ.
|
||||
|
||||
### Follow-up #3 (يوم 7 — قرار)
|
||||
> سأوقف المحاولات بعد هذه الرسالة. لو هذا توقيت غير مناسب، حدد لي شهر تجارب أخرى — وأذكّرك. مكتب مفتوح دائماً.
|
||||
|
||||
كل القوالب تمر `safety_eval` + `saudi_tone_eval` قبل الإرسال.
|
||||
|
||||
---
|
||||
|
||||
## 8. Daily Routine لإدارة الـ Board
|
||||
|
||||
### الصباح (15 دقيقة)
|
||||
- افتح الـ Sheet.
|
||||
- صفّ حسب `next_step` (date asc).
|
||||
- نفّذ الـ next_step لكل prospect وصلت تاريخه.
|
||||
- شغّل `paid_beta_daily_scorecard.py`.
|
||||
|
||||
### الظهر (15 دقيقة)
|
||||
- أضف prospects الجدد (5–10 يومياً).
|
||||
- خصّص الرسالة لكل واحد (اسم + قطاع + city + why_now).
|
||||
- اعتمد drafts.
|
||||
|
||||
### آخر اليوم (10 دقائق)
|
||||
- حدّث `reply_status` للذين ردّوا.
|
||||
- حدّث `next_step` لكل prospect نشط.
|
||||
- شغّل `paid_beta_daily_scorecard.py --json` واحفظه يومياً.
|
||||
|
||||
---
|
||||
|
||||
## 9. Privacy & PDPL
|
||||
|
||||
- **لا تشارك** هذا الـ Sheet بصلاحيات edit مع أحد.
|
||||
- **لا تخزّن** أرقام واتساب لأشخاص لم يوافقوا opt-in.
|
||||
- **لا تنسخ** الـ Sheet إلى أدوات خارجية بدون اتفاقية data processing.
|
||||
- **احذف** البيانات بعد 90 يوم لمن لم يرد ولم يطلب nurture.
|
||||
- **سجّل** كل export في Action Ledger.
|
||||
|
||||
---
|
||||
|
||||
## 10. مثال صف كامل
|
||||
|
||||
```
|
||||
| company | شركة الأثاث المتقدم |
|
||||
| person | أحمد العتيبي |
|
||||
| segment | b2b_company |
|
||||
| source | personal_network |
|
||||
| channel | linkedin_dm_manual |
|
||||
| message_sent | 2026-05-01 |
|
||||
| reply_status | positive |
|
||||
| demo_booked | 2026-05-03 |
|
||||
| diagnostic_sent| 2026-05-04 |
|
||||
| pilot_offered | 2026-05-05 |
|
||||
| price | 499 |
|
||||
| paid | pending_invoice |
|
||||
| proof_pack_sent| null |
|
||||
| next_step | 2026-05-06: متابعة دفع invoice |
|
||||
| notes | اهتم بـ partnerships في الرياض |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Sheet template (CSV header للنسخ)
|
||||
|
||||
```csv
|
||||
company,person,segment,source,channel,message_sent,reply_status,demo_booked,diagnostic_sent,pilot_offered,price,paid,proof_pack_sent,next_step,notes
|
||||
```
|
||||
|
||||
ضع هذا الصف كـ header في Google Sheet جديد. ابدأ.
|
||||
|
||||
---
|
||||
|
||||
## 12. القرار
|
||||
|
||||
```
|
||||
الـ Board ليس "نظاماً".
|
||||
الـ Board هو "الذاكرة العاملة" لأسبوعك.
|
||||
بدون الـ Board: prospects ينسون، follow-ups تضيع، payments تتأخر.
|
||||
مع الـ Board: 50 prospect → 5 ردود → 3 ديمو → 1 paid.
|
||||
```
|
||||
@ -139,18 +139,69 @@
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<span class="badge">Private Beta — متاح اليوم</span>
|
||||
<h1>مدير نمو عربي <span>للشركات السعودية</span></h1>
|
||||
<span class="badge">Private Beta — Pilot 499 ريال يبدأ اليوم</span>
|
||||
<h1>10 فرص B2B + رسائل عربية + متابعة <span>خلال 48 ساعة</span></h1>
|
||||
<p class="subtitle">
|
||||
Dealix يعطيك 10 فرص B2B خلال 10 دقائق، يكتب الرسائل بالعربي،
|
||||
ويطلع لك Proof Pack — وأنت توافق قبل أي تواصل.
|
||||
Dealix هو Saudi Revenue Execution OS — مش CRM، ولا WhatsApp bot، ولا lead scraper.
|
||||
<br/>
|
||||
<strong style="color: var(--brand);">Pilot 7 أيام بـ 499 ريال فقط.</strong>
|
||||
تسليم خلال 48 ساعة. لا إرسال خارجي بدون موافقتك.
|
||||
</p>
|
||||
<a href="mailto:bassam.m.assiri@gmail.com?subject=Pilot%20499%20-%20%5Baسم%20الشركة%5D&body=الاسم%3A%0Aالشركة%3A%0Aالقطاع%3A%0Aالمدينة%3A%0Aالعميل%20المثالي%3A" class="cta">احجز Pilot 499 الآن</a>
|
||||
<a href="#what-you-get" class="cta secondary">شاهد ماذا تحصل</a>
|
||||
<p style="margin-top: 18px; color: var(--muted); font-size: 14px;">
|
||||
أو ضمان: لو ما عجبك خلال 7 أيام، تستردّ كامل المبلغ — أو نحوّله Case Study مجاني.
|
||||
</p>
|
||||
<a href="mailto:bassam.m.assiri@gmail.com?subject=Dealix%20Private%20Beta" class="cta">احجز Pilot الآن</a>
|
||||
<a href="#demo" class="cta secondary">شاهد ديمو 12 دقيقة</a>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section>
|
||||
<main style="margin-bottom: 0;">
|
||||
<section style="background: linear-gradient(135deg, rgba(255,209,102,0.08), rgba(239,71,111,0.06)); border: 1px solid rgba(255,209,102,0.3); margin-top: 0;">
|
||||
<h2 style="color: var(--brand);">عرض اليوم — Pilot 499 ريال</h2>
|
||||
<div class="pricing-grid">
|
||||
<div class="price-card" style="border: 2px solid var(--brand);">
|
||||
<div class="label">First 10 Opportunities Sprint</div>
|
||||
<div class="price">499 ر.س</div>
|
||||
<div style="color: var(--good); font-weight: 700;">يبدأ خلال 24 ساعة</div>
|
||||
<ul style="margin-top: 10px; font-size: 14px;">
|
||||
<li>10 فرص B2B بأسماء حقيقية</li>
|
||||
<li>10 رسائل عربية جاهزة</li>
|
||||
<li>خطة متابعة 7 أيام</li>
|
||||
<li>Proof Pack نهائي</li>
|
||||
<li>تسليم ≤ 48 ساعة</li>
|
||||
</ul>
|
||||
<a href="mailto:bassam.m.assiri@gmail.com?subject=Pilot%20499%20-%20%5Bاسم%20الشركة%5D" class="cta" style="margin-top: 14px; width: 100%; text-align: center;">ابدأ Pilot الآن</a>
|
||||
</div>
|
||||
<div class="price-card">
|
||||
<div class="label">Free Diagnostic</div>
|
||||
<div class="price" style="color: var(--good);">مجاني</div>
|
||||
<div>تسليم خلال 24 ساعة</div>
|
||||
<ul style="margin-top: 10px; font-size: 14px;">
|
||||
<li>3 فرص محددة</li>
|
||||
<li>1 رسالة عربية جاهزة</li>
|
||||
<li>1 مخاطرة موجودة الآن</li>
|
||||
<li>1 توصية خدمة</li>
|
||||
</ul>
|
||||
<a href="mailto:bassam.m.assiri@gmail.com?subject=Free%20Diagnostic%20-%20%5Bاسم%20الشركة%5D" class="cta secondary" style="margin-top: 14px; width: 100%; text-align: center;">جرّب مجاناً</a>
|
||||
</div>
|
||||
<div class="price-card">
|
||||
<div class="label">Growth OS Monthly</div>
|
||||
<div class="price">2,999 ر.س/شهر</div>
|
||||
<div>اشتراك مستمر</div>
|
||||
<ul style="margin-top: 10px; font-size: 14px;">
|
||||
<li>30+ فرصة شهرياً</li>
|
||||
<li>متابعة + Reply classifier</li>
|
||||
<li>Proof Pack أسبوعي</li>
|
||||
<li>Weekly check-in</li>
|
||||
</ul>
|
||||
<span style="display: block; margin-top: 14px; color: var(--muted); font-size: 13px;">يُقدَّم بعد Pilot ناجح فقط.</span>
|
||||
</div>
|
||||
</div>
|
||||
<p style="margin-top: 18px; color: var(--muted); font-size: 14px;">
|
||||
الدفع عبر Moyasar (invoice يدوي). لا API charge. لا اشتراك تلقائي.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section id="what-you-get">
|
||||
<h2>وعد المنتج</h2>
|
||||
<p>خلال 7 أيام، نطلع لك:</p>
|
||||
<ul>
|
||||
@ -163,27 +214,6 @@
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>الأسعار</h2>
|
||||
<div class="pricing-grid">
|
||||
<div class="price-card">
|
||||
<div class="label">Pilot 7 أيام</div>
|
||||
<div class="price">499 ريال</div>
|
||||
<div>أو مجاني مقابل case study</div>
|
||||
</div>
|
||||
<div class="price-card">
|
||||
<div class="label">Paid Pilot 30 يوم</div>
|
||||
<div class="price">1,500–3,000 ريال</div>
|
||||
<div>إعداد + Pilot موسّع</div>
|
||||
</div>
|
||||
<div class="price-card">
|
||||
<div class="label">Growth OS شهري</div>
|
||||
<div class="price">2,999 ريال</div>
|
||||
<div>اشتراك مستمر</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>الفرق عن المنافسين</h2>
|
||||
<ul>
|
||||
@ -239,14 +269,17 @@
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>جاهز نبدأ؟</h2>
|
||||
<section style="background: linear-gradient(135deg, rgba(255,209,102,0.08), rgba(6,214,160,0.06)); border: 1px solid rgba(255,209,102,0.3);">
|
||||
<h2 style="color: var(--brand);">جاهز نبدأ؟ — Pilot 499 ريال يبدأ خلال 24 ساعة</h2>
|
||||
<p>
|
||||
Pilot يبدأ يوم الأحد التالي.
|
||||
أرسل لي اسمك + اسم شركتك + قطاعك + مدينتك،
|
||||
وأرتّب لك ديمو 12 دقيقة هذا الأسبوع.
|
||||
أرسل لي: اسمك + اسم شركتك + قطاعك + مدينتك + عميلك المثالي.
|
||||
خلال 24 ساعة يصلك Free Diagnostic. خلال 48 ساعة Pilot كامل (10 فرص + 10 رسائل + متابعة).
|
||||
</p>
|
||||
<a href="mailto:bassam.m.assiri@gmail.com?subject=Dealix%20Private%20Beta%20Pilot" class="cta">احجز Pilot الآن</a>
|
||||
<p style="margin: 14px 0; color: var(--good); font-weight: 700;">
|
||||
ضمان: لو ما عجبك خلال 7 أيام، تستردّ كامل المبلغ.
|
||||
</p>
|
||||
<a href="mailto:bassam.m.assiri@gmail.com?subject=Pilot%20499%20-%20%5Bاسم%20الشركة%5D&body=الاسم%3A%0Aالشركة%3A%0Aالقطاع%3A%0Aالمدينة%3A%0Aالعميل%20المثالي%3A" class="cta">احجز Pilot 499 الآن</a>
|
||||
<a href="mailto:bassam.m.assiri@gmail.com?subject=Free%20Diagnostic%20-%20%5Bاسم%20الشركة%5D" class="cta secondary">جرّب Free Diagnostic</a>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
|
||||
274
dealix/scripts/paid_beta_daily_scorecard.py
Normal file
274
dealix/scripts/paid_beta_daily_scorecard.py
Normal file
@ -0,0 +1,274 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Paid Beta Daily Scorecard — تتبّع التقدّم اليومي نحو أول إيراد.
|
||||
|
||||
كل يوم في Paid Beta، شغّل:
|
||||
|
||||
python scripts/paid_beta_daily_scorecard.py \\
|
||||
--messages 25 --replies 4 --demos 2 --pilots 1 --payments 0 --proof-packs 0
|
||||
|
||||
أو بصيغة JSON للأتمتة:
|
||||
|
||||
python scripts/paid_beta_daily_scorecard.py \\
|
||||
--messages 25 --replies 4 --demos 2 --pilots 1 --payments 1 --proof-packs 0 --json
|
||||
|
||||
الهدف خلال 7 أيام:
|
||||
70 تواصل يدوي / 15 رد / 7 ديمو / 3 pilots / 1–2 paid / 1 Proof Pack على الأقل.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from dataclasses import asdict, dataclass
|
||||
from datetime import date
|
||||
|
||||
|
||||
# ----- Targets -----
|
||||
|
||||
WEEKLY_TARGETS = {
|
||||
"messages": {"min": 50, "stretch": 70},
|
||||
"replies": {"min": 5, "stretch": 15},
|
||||
"demos": {"min": 3, "stretch": 7},
|
||||
"pilots": {"min": 2, "stretch": 3},
|
||||
"payments": {"min": 1, "stretch": 2},
|
||||
"proof_packs": {"min": 1, "stretch": 1},
|
||||
}
|
||||
|
||||
DAILY_TARGETS = {
|
||||
# ÷ 7 (مدوّر للأعلى) لأي metric
|
||||
"messages": 10,
|
||||
"replies": 1,
|
||||
"demos": 1,
|
||||
"pilots": 0, # ≥1 خلال الأسبوع
|
||||
"payments": 0, # ≥1 خلال الأسبوع
|
||||
"proof_packs": 0, # ≥1 خلال الأسبوع
|
||||
}
|
||||
|
||||
|
||||
# ----- Computation -----
|
||||
|
||||
@dataclass
|
||||
class Scorecard:
|
||||
as_of: str
|
||||
messages: int
|
||||
replies: int
|
||||
demos: int
|
||||
pilots: int
|
||||
payments: int
|
||||
proof_packs: int
|
||||
reply_rate: float
|
||||
demo_rate: float
|
||||
pilot_rate: float
|
||||
payment_rate: float
|
||||
daily_verdict: str
|
||||
weekly_verdict: str
|
||||
next_actions: list[str]
|
||||
|
||||
|
||||
def _safe_div(a: int, b: int) -> float:
|
||||
return round(a / b, 3) if b > 0 else 0.0
|
||||
|
||||
|
||||
def _daily_verdict(metrics: dict[str, int]) -> str:
|
||||
"""Compare today's metrics to daily targets."""
|
||||
misses = []
|
||||
for key, target in DAILY_TARGETS.items():
|
||||
if target == 0:
|
||||
continue
|
||||
if metrics[key] < target:
|
||||
misses.append(f"{key}: {metrics[key]}/{target}")
|
||||
if not misses:
|
||||
return "ON_TRACK"
|
||||
if len(misses) == 1:
|
||||
return f"BEHIND on {misses[0]}"
|
||||
return f"OFF_TRACK: {', '.join(misses)}"
|
||||
|
||||
|
||||
def _weekly_verdict(metrics: dict[str, int]) -> str:
|
||||
"""Compare cumulative-week metrics to weekly targets (assumes the input is week-to-date totals)."""
|
||||
blockers = []
|
||||
misses = []
|
||||
for key, t in WEEKLY_TARGETS.items():
|
||||
v = metrics[key]
|
||||
if v < t["min"]:
|
||||
blockers.append(f"{key} {v}/{t['min']}")
|
||||
elif v < t["stretch"]:
|
||||
misses.append(f"{key} {v}/{t['stretch']}")
|
||||
if not blockers and not misses:
|
||||
return "WEEKLY_TARGETS_HIT"
|
||||
if blockers:
|
||||
return "BLOCKERS: " + ", ".join(blockers)
|
||||
return "STRETCH_PENDING: " + ", ".join(misses)
|
||||
|
||||
|
||||
def _next_actions(metrics: dict[str, int]) -> list[str]:
|
||||
actions: list[str] = []
|
||||
|
||||
if metrics["messages"] < DAILY_TARGETS["messages"]:
|
||||
deficit = DAILY_TARGETS["messages"] - metrics["messages"]
|
||||
actions.append(
|
||||
f"أرسل {deficit} رسالة إضافية اليوم (LinkedIn/Email/WhatsApp opt-in فقط)."
|
||||
)
|
||||
|
||||
if metrics["messages"] >= 5 and metrics["replies"] == 0:
|
||||
actions.append(
|
||||
"0 ردود مع >5 رسائل — راجع نبرة الرسالة وعدّلها (saudi_tone_eval)."
|
||||
)
|
||||
|
||||
if metrics["replies"] >= 2 and metrics["demos"] == 0:
|
||||
actions.append(
|
||||
"ردود إيجابية بدون ديمو — احجز ديمو 12 دقيقة لكل رد إيجابي اليوم."
|
||||
)
|
||||
|
||||
if metrics["demos"] >= 2 and metrics["pilots"] == 0:
|
||||
actions.append(
|
||||
"ديمو ≥2 بدون عرض Pilot — أرسل عرض Pilot 499 + Free Diagnostic لكل ديمو."
|
||||
)
|
||||
|
||||
if metrics["pilots"] >= 1 and metrics["payments"] == 0:
|
||||
actions.append(
|
||||
"Pilot معروض بدون دفع — تابع Moyasar invoice manual + رسالة متابعة دفع."
|
||||
)
|
||||
|
||||
if metrics["payments"] >= 1 and metrics["proof_packs"] == 0:
|
||||
actions.append(
|
||||
"أول دفعة وصلت — ابدأ Pilot delivery + أعد Proof Pack v1 خلال 48 ساعة."
|
||||
)
|
||||
|
||||
if not actions:
|
||||
actions.append(
|
||||
"اليوم ON_TRACK. حافظ على الإيقاع: 10 رسائل + 5 follow-ups + 1 ديمو."
|
||||
)
|
||||
|
||||
return actions
|
||||
|
||||
|
||||
def build_scorecard(
|
||||
messages: int,
|
||||
replies: int,
|
||||
demos: int,
|
||||
pilots: int,
|
||||
payments: int,
|
||||
proof_packs: int,
|
||||
as_of: str | None = None,
|
||||
) -> Scorecard:
|
||||
metrics = {
|
||||
"messages": messages,
|
||||
"replies": replies,
|
||||
"demos": demos,
|
||||
"pilots": pilots,
|
||||
"payments": payments,
|
||||
"proof_packs": proof_packs,
|
||||
}
|
||||
return Scorecard(
|
||||
as_of=as_of or date.today().isoformat(),
|
||||
messages=messages,
|
||||
replies=replies,
|
||||
demos=demos,
|
||||
pilots=pilots,
|
||||
payments=payments,
|
||||
proof_packs=proof_packs,
|
||||
reply_rate=_safe_div(replies, messages),
|
||||
demo_rate=_safe_div(demos, replies),
|
||||
pilot_rate=_safe_div(pilots, demos),
|
||||
payment_rate=_safe_div(payments, pilots),
|
||||
daily_verdict=_daily_verdict(metrics),
|
||||
weekly_verdict=_weekly_verdict(metrics),
|
||||
next_actions=_next_actions(metrics),
|
||||
)
|
||||
|
||||
|
||||
# ----- Rendering -----
|
||||
|
||||
def render_text(card: Scorecard) -> str:
|
||||
lines = [
|
||||
"════════════════════════════════════════════════",
|
||||
f" Paid Beta Daily Scorecard — {card.as_of}",
|
||||
"════════════════════════════════════════════════",
|
||||
"",
|
||||
"اليوم:",
|
||||
f" 📨 رسائل أُرسلت: {card.messages:>3} (يومي ≥10)",
|
||||
f" 💬 ردود إيجابية: {card.replies:>3} (يومي ≥1)",
|
||||
f" 📅 ديمو محجوز: {card.demos:>3} (يومي ≥1)",
|
||||
f" 🚀 Pilots معروضة: {card.pilots:>3} (أسبوعي ≥2)",
|
||||
f" 💳 دفعات وصلت: {card.payments:>3} (أسبوعي ≥1)",
|
||||
f" 📦 Proof Packs مرسلة: {card.proof_packs:>3} (أسبوعي ≥1)",
|
||||
"",
|
||||
"Conversion Rates:",
|
||||
f" reply_rate = {card.reply_rate:.1%}",
|
||||
f" demo_rate = {card.demo_rate:.1%} (replies → demos)",
|
||||
f" pilot_rate = {card.pilot_rate:.1%} (demos → pilots)",
|
||||
f" payment_rate = {card.payment_rate:.1%} (pilots → paid)",
|
||||
"",
|
||||
f"Daily Verdict: {card.daily_verdict}",
|
||||
f"Weekly Verdict: {card.weekly_verdict}",
|
||||
"",
|
||||
"Next Actions:",
|
||||
]
|
||||
for i, action in enumerate(card.next_actions, 1):
|
||||
lines.append(f" {i}. {action}")
|
||||
lines.extend([
|
||||
"",
|
||||
"════════════════════════════════════════════════",
|
||||
"Targets: 50–70 messages / 5–15 replies / 3–7 demos /",
|
||||
" 2–3 pilots / 1–2 paid / 1+ proof pack الأسبوع.",
|
||||
"════════════════════════════════════════════════",
|
||||
])
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def render_json(card: Scorecard) -> str:
|
||||
return json.dumps(asdict(card), ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
# ----- CLI -----
|
||||
|
||||
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
||||
p = argparse.ArgumentParser(
|
||||
description="Paid Beta daily scorecard — track manual outreach progress.",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=(
|
||||
"Examples:\n"
|
||||
" python scripts/paid_beta_daily_scorecard.py "
|
||||
"--messages 25 --replies 4 --demos 2 --pilots 1 --payments 0 --proof-packs 0\n"
|
||||
" python scripts/paid_beta_daily_scorecard.py "
|
||||
"--messages 25 --replies 4 --demos 2 --pilots 1 --payments 1 --proof-packs 0 --json"
|
||||
),
|
||||
)
|
||||
p.add_argument("--messages", type=int, default=0, help="رسائل أُرسلت")
|
||||
p.add_argument("--replies", type=int, default=0, help="ردود إيجابية")
|
||||
p.add_argument("--demos", type=int, default=0, help="ديمو محجوز")
|
||||
p.add_argument("--pilots", type=int, default=0, help="Pilots معروضة")
|
||||
p.add_argument("--payments", type=int, default=0, help="دفعات وصلت")
|
||||
p.add_argument("--proof-packs", dest="proof_packs", type=int, default=0,
|
||||
help="Proof Packs مُسلَّمة")
|
||||
p.add_argument("--as-of", type=str, default=None,
|
||||
help="تاريخ (YYYY-MM-DD أو 'today')")
|
||||
p.add_argument("--json", action="store_true", help="إخراج JSON")
|
||||
return p.parse_args(argv)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = parse_args(argv)
|
||||
as_of = None if (args.as_of in (None, "today")) else args.as_of
|
||||
card = build_scorecard(
|
||||
messages=args.messages,
|
||||
replies=args.replies,
|
||||
demos=args.demos,
|
||||
pilots=args.pilots,
|
||||
payments=args.payments,
|
||||
proof_packs=args.proof_packs,
|
||||
as_of=as_of,
|
||||
)
|
||||
output = render_json(card) if args.json else render_text(card)
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
except (AttributeError, OSError):
|
||||
pass
|
||||
print(output)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
125
dealix/tests/unit/test_paid_beta_scorecard.py
Normal file
125
dealix/tests/unit/test_paid_beta_scorecard.py
Normal file
@ -0,0 +1,125 @@
|
||||
"""Unit tests for the Paid Beta Daily Scorecard script."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
SCRIPTS_DIR = REPO_ROOT / "scripts"
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
import paid_beta_daily_scorecard as pbds # noqa: E402
|
||||
|
||||
|
||||
# ----- core scorecard logic -----
|
||||
|
||||
def test_zero_input_yields_off_track():
|
||||
card = pbds.build_scorecard(0, 0, 0, 0, 0, 0, as_of="2026-05-01")
|
||||
assert card.messages == 0
|
||||
assert card.reply_rate == 0.0
|
||||
# 0 messages, 0 replies, 0 demos → daily target on messages is breached.
|
||||
assert "OFF_TRACK" in card.daily_verdict or "BEHIND" in card.daily_verdict
|
||||
assert any("رسالة" in a or "messages" in a.lower() for a in card.next_actions)
|
||||
|
||||
|
||||
def test_full_day_on_track():
|
||||
card = pbds.build_scorecard(10, 1, 1, 0, 0, 0, as_of="2026-05-01")
|
||||
assert card.daily_verdict == "ON_TRACK"
|
||||
# Weekly is still in early days; expect blockers but daily is fine.
|
||||
assert "BLOCKERS" in card.weekly_verdict
|
||||
|
||||
|
||||
def test_high_message_zero_reply_triggers_tone_action():
|
||||
card = pbds.build_scorecard(20, 0, 0, 0, 0, 0)
|
||||
assert any("نبرة" in a or "tone" in a.lower() for a in card.next_actions)
|
||||
|
||||
|
||||
def test_payment_received_advances_proof_pack_action():
|
||||
card = pbds.build_scorecard(20, 4, 2, 1, 1, 0)
|
||||
assert any("Proof Pack" in a for a in card.next_actions)
|
||||
|
||||
|
||||
def test_weekly_targets_hit_when_full_week():
|
||||
card = pbds.build_scorecard(70, 15, 7, 3, 2, 1)
|
||||
assert card.weekly_verdict == "WEEKLY_TARGETS_HIT"
|
||||
|
||||
|
||||
def test_conversion_rates_computed():
|
||||
card = pbds.build_scorecard(25, 5, 2, 1, 1, 0)
|
||||
assert card.reply_rate == 0.2
|
||||
assert card.demo_rate == 0.4
|
||||
assert card.pilot_rate == 0.5
|
||||
assert card.payment_rate == 1.0
|
||||
|
||||
|
||||
# ----- rendering -----
|
||||
|
||||
def test_render_text_contains_arabic_labels():
|
||||
card = pbds.build_scorecard(25, 4, 2, 1, 0, 0)
|
||||
text = pbds.render_text(card)
|
||||
assert "Paid Beta Daily Scorecard" in text
|
||||
assert "رسائل أُرسلت" in text
|
||||
assert "Daily Verdict" in text
|
||||
assert "Weekly Verdict" in text
|
||||
assert "Next Actions" in text
|
||||
|
||||
|
||||
def test_render_json_is_valid_json():
|
||||
card = pbds.build_scorecard(25, 4, 2, 1, 0, 0, as_of="2026-05-01")
|
||||
output = pbds.render_json(card)
|
||||
parsed = json.loads(output)
|
||||
assert parsed["messages"] == 25
|
||||
assert parsed["as_of"] == "2026-05-01"
|
||||
assert "next_actions" in parsed
|
||||
assert isinstance(parsed["next_actions"], list)
|
||||
|
||||
|
||||
# ----- CLI -----
|
||||
|
||||
def test_cli_main_text_mode(capsys):
|
||||
rc = pbds.main([
|
||||
"--messages", "25", "--replies", "4",
|
||||
"--demos", "2", "--pilots", "1",
|
||||
"--payments", "0", "--proof-packs", "0",
|
||||
])
|
||||
assert rc == 0
|
||||
captured = capsys.readouterr()
|
||||
assert "Paid Beta Daily Scorecard" in captured.out
|
||||
assert "25" in captured.out
|
||||
|
||||
|
||||
def test_cli_main_json_mode(capsys):
|
||||
rc = pbds.main([
|
||||
"--messages", "25", "--replies", "4",
|
||||
"--demos", "2", "--pilots", "1",
|
||||
"--payments", "1", "--proof-packs", "0",
|
||||
"--json",
|
||||
])
|
||||
assert rc == 0
|
||||
captured = capsys.readouterr()
|
||||
payload = json.loads(captured.out)
|
||||
assert payload["messages"] == 25
|
||||
assert payload["payments"] == 1
|
||||
assert payload["weekly_verdict"]
|
||||
|
||||
|
||||
def test_cli_as_of_today(capsys):
|
||||
rc = pbds.main(["--messages", "10", "--as-of", "today"])
|
||||
assert rc == 0
|
||||
captured = capsys.readouterr()
|
||||
# 'today' should resolve to a real date string in the output (YYYY-MM-DD).
|
||||
assert "20" in captured.out # any year starts with "20" in our era
|
||||
|
||||
|
||||
def test_cli_as_of_explicit(capsys):
|
||||
rc = pbds.main([
|
||||
"--messages", "10", "--as-of", "2026-04-30",
|
||||
"--json",
|
||||
])
|
||||
assert rc == 0
|
||||
captured = capsys.readouterr()
|
||||
payload = json.loads(captured.out)
|
||||
assert payload["as_of"] == "2026-04-30"
|
||||
Loading…
Reference in New Issue
Block a user