# Flatlogic CI/CD + External DB + Ingestion API هذا الإعداد يجعل المشروع يعمل بهذه الصورة: - **GitHub** هو مصدر الحقيقة للكود. - **Bolt / Replit** يدفعان التعديلات إلى نفس المستودع أو يرسلان `repository_dispatch`. - **GitHub Actions** تبني المشروع وتتحقق منه ثم تنشره إلى VM الخاص بـ Flatlogic. - **Flatlogic / API Server** يدير بيانات المنتجات القادمة من أدوات السحب وويبهوكات شي إن. - **Supabase / PostgreSQL** هو مخزن البيانات الخارجي للمنتجات والفئات وسجل أحداث التكامل. ## ما تمت إضافته - `.github/workflows/ci.yml` - Typecheck + Build لكل Push / Pull Request. - `.github/workflows/deploy-flatlogic.yml` - ينشر تلقائيًا إلى VM عند التحديث على `main` أو `master`. - يدعم `repository_dispatch` لأنواع: - `bolt_sync` - `replit_sync` - `flatlogic_deploy` - `scripts/flatlogic-deploy.sh` - يسحب آخر نسخة من GitHub. - يثبت الحزم. - يشغل `typecheck` و `build`. - يطبق schema قاعدة البيانات عبر Drizzle. - يعيد تشغيل `extra-store` و `flatlogic-api` عبر PM2. - `.env.example` - كل متغيرات البيئة المطلوبة للـ DB والـ API والأمان. - API endpoints جديدة داخل `artifacts/api-server`. ## الأسرار المطلوبة في GitHub Actions أضف هذه القيم في **GitHub → Settings → Secrets and variables → Actions**: ### أسرار النشر إلى Flatlogic VM - `FLATLOGIC_HOST` - `FLATLOGIC_USER` - `FLATLOGIC_SSH_KEY` - `FLATLOGIC_PROJECT_DIR` - `FLATLOGIC_DEPLOY_BRANCH` (اختياري) ### أسرار الـ backend - `DATABASE_URL` - `DB_SSL` = `require` - `DB_POOL_MAX` = `20` - `DB_QUERY_TIMEOUT_MS` = `15000` - `DB_STATEMENT_TIMEOUT_MS` = `15000` - `ADMIN_TOKEN` - `API_INGEST_KEY` - `WEBHOOK_SECRET` - `SHEIN_WEBHOOK_SECRET` - `API_PORT` = `8080` - `STORE_PORT` = `3001` ## إعداد قاعدة البيانات الخارجية (Supabase / PostgreSQL) الحد الأدنى المقترح لاستيعاب 2000 منتج من Extra + Shein: - استخدم **Postgres خارجي** أو **Supabase**. - يفضل في Supabase استخدام **transaction pooler** داخل `DATABASE_URL`. - الإعدادات الافتراضية المضافة في الكود: - `DB_POOL_MAX=20` - `DB_QUERY_TIMEOUT_MS=15000` - `DB_STATEMENT_TIMEOUT_MS=15000` - `keepAlive=true` - أضف الـ schema بالأمر: ```bash pnpm --filter @workspace/db run push ``` > ملاحظة: الجدول `products` صار يدعم الآن `source`, `external_id`, `source_url`, `currency`, `availability`, `metadata`, `last_synced_at` مع فهارس مخصصة للبحث والتزامن. ## API Endpoints الجديدة ### 1) Bulk ingestion للمنتجات `POST /api/ingest/products/bulk` Headers: ```text x-api-key: content-type: application/json ``` Body مثال: ```json { "source": "shein", "webhook_id": "apify-run-123", "products": [ { "external_id": "shein-10001", "sku": "SKU-10001", "name": "فستان صيفي", "brand": "SHEIN", "price": 149, "original_price": 199, "stock": 25, "availability": "in_stock", "sizes": ["S", "M", "L"], "colors": ["Black", "Pink"], "images": ["https://example.com/1.jpg"], "category": { "slug": "dresses", "name": "فساتين" }, "source_url": "https://example.com/product/10001" } ] } ``` ### 2) Upsert منتج مفرد `POST /api/ingest/products/upsert` نفس الحماية عبر `x-api-key`. ### 3) Webhook تحديثات شي إن `POST /api/webhooks/shein/products` Headers: ```text x-api-key: x-webhook-signature: sha256= content-type: application/json ``` Body مثال: ```json { "webhook_id": "shein-webhook-987", "event": "price.updated", "products": [ { "external_id": "shein-10001", "price": 139, "stock": 12, "availability": "low_stock", "sizes": ["S", "M"] } ] } ``` ### 4) Pipeline status `GET /api/integrations/pipeline/status` - محمي بـ `Authorization: Bearer ` - يعرض: - حالة إعداد الأمان - حالة الـ DB - عدد المنتجات حسب المصدر - آخر أحداث التكامل ## ربط Bolt / Replit مع GitHub أفضل سيناريو: 1. اجعل **Bolt** أو **Replit** يدفعان إلى نفس مستودع GitHub. 2. كل Push إلى `main` يشغل: - `ci.yml` - ثم `deploy-flatlogic.yml` 3. النتيجة: يتم تحديث الموقع والـ backend تلقائيًا. إذا كانت الأداة لا تدفع مباشرة إلى GitHub، استخدم `repository_dispatch` من GitHub API بنوع: - `bolt_sync` - `replit_sync` ## ملاحظات تشغيلية - الواجهة الأمامية الآن تدعم `VITE_API_BASE_URL` إذا أردت backend مختلفًا عن نفس الدومين. - في وضع التطوير، Vite يمرر `/api` إلى `http://127.0.0.1:8080` عبر proxy. - إذا لم تكن أسرار الـ backend موجودة، فسيستمر المتجر الأمامي بالعمل، لكن تشغيل خدمة الـ API سيتم تخطيه أثناء النشر.