chore(dealix): launch runbooks, staging env templates, SQLite init on startup, product journey test

Co-authored-by: VoXc2 <VoXc2@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-04-12 11:01:09 +00:00
parent 8c3d91c070
commit 69f5082e5e
No known key found for this signature in database
12 changed files with 241 additions and 2 deletions

View File

@ -0,0 +1,36 @@
# Staging template — copy to `.env` on the staging host (never commit `.env`).
# Full variable list: `.env.example`. Phase-2 integrations checklist: `docs/INTEGRATION_MASTER_AR.md`
# and `backend/.env.phase2.example`.
ENVIRONMENT=staging
DEFAULT_TIMEZONE=Asia/Riyadh
# Docker Compose: keep @db / @redis hostnames. Bare metal: use 127.0.0.1 and matching ports.
DB_NAME=salesflow
DB_USER=salesflow
DB_PASSWORD=REPLACE_ME_STRONG
DATABASE_URL=postgresql+asyncpg://salesflow:REPLACE_ME_STRONG@db:5432/salesflow
REDIS_URL=redis://redis:6379/0
SECRET_KEY=REPLACE_ME_RANDOM_32PLUS_CHARS
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_DAYS=7
# Public URLs for your staging domain (CORS + webhooks)
API_URL=https://api-staging.example.com
FRONTEND_URL=https://app-staging.example.com
NEXT_PUBLIC_API_URL=https://api-staging.example.com
WEBHOOK_BASE_URL=https://api-staging.example.com/api/v1/webhooks
# LLM — set at least one real key for AI features in staging
OPENAI_API_KEY=
GROQ_API_KEY=
# Channels — fill only what you will smoke-test (see launch checklist)
WHATSAPP_API_TOKEN=
WHATSAPP_PHONE_NUMBER_ID=
WHATSAPP_VERIFY_TOKEN=
SMTP_USER=
SMTP_PASSWORD=

View File

@ -28,10 +28,12 @@ Frontend: `http://localhost:3000`
**If the browser shows connection refused on `:3000` or `:8000`:** nothing is listening on that port yet. Start the stack (`docker compose up` from this folder) or run `uvicorn` / `npm run dev` manually. Confirm with `curl -sSf http://127.0.0.1:8000/api/v1/health` and ensure the browser is on the same machine as the server (not WSL/remote without port forwarding).
**Without Docker:** install Python 3.12+ and Node 22+, copy `.env` and `frontend/.env.local`, run Postgres/Redis (or point `DATABASE_URL` / `REDIS_URL` at existing instances), then `cd backend && uvicorn app.main:app --reload --host 0.0.0.0 --port 8000` and `cd frontend && npm run dev`.
**Without Docker:** install Python 3.12+ and Node 22+, copy `.env` and `frontend/.env.local`, run Postgres/Redis (or point `DATABASE_URL` / `REDIS_URL` at existing instances), then `cd backend && uvicorn app.main:app --reload --host 0.0.0.0 --port 8000` and `cd frontend && npm run dev`. If `DATABASE_URL` uses SQLite (`sqlite+aiosqlite`), the API runs `init_db()` on startup so tables exist for local smoke tests; production should use Postgres + Alembic migrations.
**E2E locally:** after `npm ci`, run `npx playwright install chromium` once, then `npm run test:e2e` (matches CI).
**Staging env templates:** `.env.staging.example` (repo root) and `frontend/.env.staging.example` — copy to `.env` / `frontend/.env.local` on the host; see `docs/STAGING_ENV_CHECKLIST.md`.
**Customer onboarding (B2B):** `GET /api/v1/customer-onboarding/journey` and `docs/CUSTOMER_OS_ONBOARDING_AR.md`. Dashboard tab: **مسار التشغيل مع العميل**.
**Launch verification:** see `docs/LAUNCH_CHECKLIST.md`. From `salesflow-saas`: copy `frontend/.env.example` to `frontend/.env.local` and set `NEXT_PUBLIC_API_URL`. Run `.\verify-launch.ps1 -HttpCheck -SoftReady` (use `-BaseUrl` if the API is not on port 8000).

View File

@ -61,6 +61,8 @@ async def get_db():
async def init_db():
import app.models # noqa: F401 — register all models on Base.metadata before create_all
async with engine.begin() as conn:
if not IS_SQLITE:
for ext in ["CREATE EXTENSION IF NOT EXISTS vector",

View File

@ -12,6 +12,7 @@ from contextlib import asynccontextmanager
import asyncio
from app.config import get_settings
from app.database import IS_SQLITE, init_db
from app.api.v1.router import api_router
from app.flows.self_improvement_flow import self_improvement_flow
from app.middleware.internal_api import InternalApiTokenMiddleware
@ -70,6 +71,8 @@ async def lifespan(app: FastAPI):
print(f" Environment: {settings.ENVIRONMENT}")
print(f" LLM Primary: {settings.LLM_PRIMARY_PROVIDER}")
print(f" LLM Fallback: {settings.LLM_FALLBACK_PROVIDER}")
if IS_SQLITE:
await init_db()
yield
# Shutdown
stop_event.set()

View File

@ -0,0 +1,64 @@
"""
Staging / CI مسار منتج واحد + دخان قناة (بريد عبر outreach بدون إرسال SMTP).
يُكمّل test_new_subscriber_journey ويُثبت أن القنوات تستجيب بعد تسجيل مستخدم.
"""
from __future__ import annotations
import uuid
import pytest
from httpx import ASGITransport, AsyncClient
from app.main import app
@pytest.mark.launch
@pytest.mark.asyncio
async def test_staging_happy_path_dashboard_and_email_channel_draft():
suffix = uuid.uuid4().hex[:14]
email = f"staging_path_{suffix}@dealix.journey.test"
password = "Staging_Secure_Pass_9"
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
reg = await ac.post(
"/api/v1/auth/register",
json={
"company_name": f"Staging Path Co {suffix}",
"company_name_ar": "شركة مسار الاختبار",
"full_name": "مالك الاختبار",
"email": email,
"password": password,
"phone": "0501112233",
"industry": "real_estate",
},
)
assert reg.status_code == 200, reg.text
token = reg.json()["access_token"]
dash = await ac.get(
"/api/v1/dashboard/overview",
headers={"Authorization": f"Bearer {token}"},
)
assert dash.status_code == 200
outreach = await ac.post(
"/api/v1/outreach",
json={
"channel": "email",
"lead": {
"name": "عميل تجريبي",
"company": "عقار الرياض",
"sector": "عقار",
},
"campaign_type": "cold_intro",
"language": "ar",
},
)
assert outreach.status_code == 200, outreach.text
body = outreach.json()
assert body.get("channel") == "email"
assert "subject" in body and "body" in body
assert len(body["subject"]) > 0 and len(body["body"]) > 0

View File

@ -0,0 +1,40 @@
# Dealix — تشغيل الستاك الكامل بـ Docker Compose
من مجلد `salesflow-saas`:
```bash
cp .env.example .env
# عدّل .env (SECRET_KEY، كلمات مرور DB، مفاتيح اختيارية)
docker compose up -d --build
docker compose ps
```
## قاعدة البيانات والبذور
```bash
make migrate
make seed
```
## Celery
الخدمات: `celery_worker`, `celery_beat`. للتحقق:
```bash
docker compose logs -f celery_worker --tail=50
```
إذا كانت الميزات (تسلسلات، مهام مجدولة) لا تعمل، راجع أن Redis و`REDIS_URL` سليمة وأن الـ worker يعمل دون أخطاء متكررة.
## إيقاف التشغيل
```bash
docker compose down
# مع حذف الحجم (احذر — يمسح بيانات Postgres المحلية):
# docker compose down -v
```
## بيئة بدون Docker
على أجهزة التطوير التي لا تتوفر فيها Docker، استخدم نفس أوامر CI: `pytest` مع SQLite و`npm run build`، وتشغيل `uvicorn` محلياً مع Postgres/Redis منفصلين أو قاعدة SQLite للاختبارات فقط — لا يغني ذلك عن اختبار staging حقيقي قبل الإنتاج.

View File

@ -10,6 +10,7 @@
- [ ] تشغيل من **أحدث** كود في المستودع:
`cd backend && py -m uvicorn app.main:app --host 0.0.0.0 --port 8000`
- [ ] **SQLite محلي فقط:** عند `DATABASE_URL=sqlite+aiosqlite://...` يُنشئ التطبيق الجداول عند الإقلاع (`init_db`) لتسهيل الاختبار؛ **الإنتاج يستخدم Postgres + Alembic** (`make migrate`) وليس الاعتماد على `create_all`.
- [ ] إذا ظهر **404** على `/api/v1/marketing/hub` أو `/api/v1/strategy/summary` فالعملية غالباً **قديمة** — أعد تشغيل `uvicorn` بعد `git pull`.
- [ ] اختبار HTTP:
`py scripts/full_stack_launch_test.py --http-only --soft-ready`
@ -31,6 +32,11 @@
- [ ] مراقبة `/api/v1/health` و `/api/v1/ready`.
- [ ] مراجعة `go-live-gate` عند التكاملات الحقيقية (قد يعيد 403 حتى اكتمال التهيئة — متوقع).
- [ ] خطة التراجع والقطع: `memory/runbooks/ROLLBACK_AND_GO_LIVE.md`.
## 6. تمييز السوق (قبل الإعلان)
- [ ] مراجعة `docs/MARKET_POSITIONING_AR.md` ومواءمة النسخ مع الميزات المفعّلة فعلياً.
---

View File

@ -0,0 +1,25 @@
# Dealix — تمييز السوق والرسالة (عربي)
## قصة قطاع: عقار في الرياض
**المشكلة:** فرق المبيعات تتلقى استفسارات من واتساب والموقع، لكن المتابعة غير موحّدة، والتأهيل يدوي، والامتثال لموافقات العملاء (PDPL) غير موثّق.
**الحل مع Dealix:** مسار واحد من Lead → تأهيل بالذكاء الاصطناعي (عربي) → تسلسل رسائل بحكم PDPL → لوحة للصفقات والموافقات. العملاء يرون **وقت أقل على التتبع** و**زيادة وضوح Pipeline**.
## مقارنة سريعة مع CRM عام (HubSpot-style)
| البعد | CRM عام | Dealix |
|--------|---------|--------|
| العربية والـ RTL | غالباً إضافة | أولاً في الواجهة والقوالب |
| واتساب كقناة أولى | يحتاج تكاملات وإعداد طويل | مسارات وقنوات مدمجة في المنتج (انظر التكاملات في `docs/INTEGRATION_MASTER_AR.md`) |
| PDPL والموافقات | مسؤولية العميل غالباً | طبقة خدمات ووثائق موجهة للسوق السعودي |
| «يوم واحد» | استيراد جهات اتصال | تشغيل سريع مع قوائم التحقق والـ staging templates |
## الامتثال كميزة
- التحقق من الموافقة قبل أي إرسال صادر مذكور في سياسة المنتج (`services/pdpl`).
- للمواد الخارجية: اذكر **PDPL** و**تسجيل الموافقات** بلغة عملاء الأعمال، دون وعود بميزات غير مفعّلة في البيئة التي تنشرونها.
## مواءمة النسخ مع المنتج الحي
قبل الحملات: راجع المسارات العامة (`/`، `/marketers`، `/strategy`) و`GET /api/v1/value-proposition/` و`GET /api/v1/customer-onboarding/journey` وتأكد أن الوعود في التسويق تطابق ما هو مُفعّل في الإنتاج.

View File

@ -0,0 +1,26 @@
# Dealix — قائمة تهيئة بيئة Staging
استخدم هذا الملف مع [LAUNCH_CHECKLIST.md](LAUNCH_CHECKLIST.md) و [INTEGRATION_MASTER_AR.md](INTEGRATION_MASTER_AR.md).
## 1) ملفات البيئة
| الملف | الإجراء |
|--------|---------|
| جذر `salesflow-saas` | انسخ [`.env.staging.example`](../.env.staging.example) إلى `.env` واستبدل القيم |
| `frontend/` | انسخ [`frontend/.env.staging.example`](../frontend/.env.staging.example) إلى `frontend/.env.local` |
| تكاملات موسعة | راجع `backend/.env.phase2.example` واملأ الأقسام التي ستفعّلها فقط |
## 2) CORS
- `FRONTEND_URL` في `.env` يجب أن يطابق أصل الواجهة (مثلاً `https://app-staging.example.com`).
- إن تغيّر النطاق، حدّث إعدادات CORS في الباكند إن لزم.
## 3) بعد التشغيل
- `GET /api/v1/health` و `GET /api/v1/ready`
- سكربت اختياري: `python scripts/full_stack_launch_test.py --http-only --soft-ready` مع `DEALIX_BASE_URL`
- جولة يدوية سريعة للواجهة (RTL): `/`، `/landing`، `/marketers`، `/strategy`، `/login`، `/register`، `/dashboard`، `/settings`، `/privacy`، `/terms`
## 4) قنوات حقيقية
لا تفعّل واتساب/بريد إنتاجي حتى اكتمال فحوص PDPL والموافقات. للـ staging اختبر عنواناً داخلياً أو رقم sandbox.

View File

@ -0,0 +1,4 @@
# Staging — copy to `.env.local` (or set in hosting dashboard). Do not commit `.env.local`.
# Must be a URL the browser can reach (HTTPS in staging/production).
NEXT_PUBLIC_API_URL=https://api-staging.example.com

View File

@ -0,0 +1,31 @@
# Dealix — بوابة الإنتاج، المراقبة، والتراجع
**مرجع:** `docs/LAUNCH_CHECKLIST.md`، `GET /api/v1/autonomous-foundation/integrations/go-live-gate`، `GET /api/v1/autonomous-foundation/integrations/live-readiness`.
## ما قبل القطع (go-live gate)
1. دمج `main` مع CI أخضر (باكند pytest، فرونت lint/build، Playwright E2E).
2. Postgres: `make migrate` (أو ما يعادله في الاستضافة) — **لا** تعتمد على `init_db()` في SQLite للإنتاج.
3. ضبط `.env` و`frontend/.env.local` (`NEXT_PUBLIC_API_URL`، `FRONTEND_URL`، CORS).
4. توقع **403** من `go-live-gate` حتى تكتمل التكاملات الحرجة — هذا متوقع إذا كانت البيئة غير مهيأة بالكامل؛ راجع `live-readiness` للتفاصيل.
## النشر
- باكند: صورة Docker أو عملية `uvicorn` خلف reverse proxy مع TLS.
- فرونت: بناء Next.js (`npm run build`) أو منصة الاستضافة المختارة؛ نفس متغيرات الـ API العامة.
## المراقبة بعد الإطلاق
- `GET /api/v1/health` — الخدمة حية.
- `GET /api/v1/ready` — جاهزية التبعيات (قاعدة، Redis، إلخ حسب التطبيق).
- سجلات الأخطاء (مثلاً Sentry) ومراقبة معدل 5xx على المسارات الحرجة.
## التراجع (rollback)
1. **التطبيق:** إعادة نشر الإصدار السابق من صورة Docker / commit المعتمد.
2. **قاعدة البيانات:** إن وُجدت ترحيلات Alembic تسبب خللاً، نفّذ `alembic downgrade` إلى المراجعة المعروفة بالاستقرار (بعد أخذ نسخة احتياطية).
3. **الإعدادات:** أعد القيم السابقة للأسرار في مدير الأسرار إن تغيّرت أثناء القطع.
## فرع الكود للنشر
استخدم **`main`** كمصدر للإنتاج بعد الدمج؛ لا تعتمد على فروع مؤقتة قديمة في سكربتات النشر.

View File

@ -41,7 +41,7 @@ apt install git -y
# 5. انسخ المشروع
git clone https://github.com/VoXc2/system-prompts-and-models-of-ai-tools.git
cd system-prompts-and-models-of-ai-tools
git checkout claude/complete-system-prompts-wqJCm
git checkout main
cd salesflow-saas
```