Back to articles

ضع تدقيق SEO في خط أنابيب النشر الخاص بك: API، رموز الخروج، ووصفات CI

SEOReport Team·
apici-cdautomationgithub-actionstechnical-seodevops

وصفة عملية لتدقيق موقعك من CI: ثلاث نقاط نهاية REST، حقول النقاط التي يمكن لبوابة البناء قراءتها، والفرق بين الانحدار الحقيقي ووميض البنية التحتية.

الانحدارات التقنية التي تكلف أكثر رؤية غير مرئية في مراجعة الكود. علامة canonical التي تبدأ بالإشارة إلى المضيف الخطأ، كتلة hreflang تفقد مرجعيتها، رأس Content-Security-Policy يُزال من إعداد reverse-proxy، مسار يضع محتواه خلف hydration — كل واحد منها يمر في diff يبدو جيداً ويجتاز كل اختبار لديك. تظهر بعد أسابيع، في مخطط حركة المرور، بعد فترة طويلة من الالتزام الذي تسبب فيها وتغلق من الرؤية.

الإصلاح هيكلية: نفّذ التدقيق عند النشر، وليس في اليوم الذي يتذكر فيه شخص ما. كل تقرير SEOReport متاح عبر REST، يحمل الرد كتلة نقاط رقمية، ويمكن لسكريبت shell تحويل تلك الكتلة إلى رمز خروج. هذا هو الآلية الكاملة.

أربع فئات انحدار لا يلتقطها سوى الآلة في الوقت المناسب

تصمد أربعة أوضاع فشل أمام المراجعة البشرية بشكل خاص، ويستحق تسميتها بشكل ملموس، لأنها ما تحميه البوابة فعلياً.

Hreflang. تعتمد المجموعة على المرجعية الذاتية، وروابط العودة، وx-default معقول، وعناوين URL صحيحة الصياغة، وبدائل قابلة للفهرسة يشير canonical كل منها إلى نفسه. ترحيل CMS يعيد كتابة أنماط URL يمكن أن يكسر روابط العودة عبر كل لغة في آن واحد، ولا تبدو أي لغة مكسورة بمعزل.

Canonicalization. يجب أن يوجد canonical، وأن يشير إلى هدف قابل للفهرسة لا يعيد التوجيه، وأن يبقى على مضيف الموقع نفسه. أسوأ نسخة من هذا الفشل هي canonical في مرحلة التجريب يُرسل إلى الإنتاج — صفحة تُنادي بهدوء مضيفاً لا تريد فهرسته.

Security headers. Content-Security-Policy، HSTS، Referrer-Policy، X-Frame-Options، X-Content-Type-Options، وPermissions-Policy. هذه موجودة في إعدادات البنية التحتية، وليس في كود التطبيق، وهذا بالضبط السبب في اختفائها أثناء تغيير proxy أو edge-config ولا يلاحظ أحد.

Render parity. يمكن أن تقدّم الصفحة نسخة في استجابة HTML ونسخة أخرى بعد تشغيل السكربتات: عنوان مختلف، أو عناوين رئيسية مفقودة، أو canonical يُحقن متأخرًا، أو نص جسم لا يوجد إلا بعد hydration. عندما وصلت بيانات render-parity data إلى حكم، كانت معظم المواقع تقدم صفحة أكثر نحافة بكثير لأي شيء يقرأ HTML كما تم تسليمه. يكفي وجود ssr: false في ملف التكوين لنقل موقع إلى ذلك المجموعة.

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

ثلاث نقاط نهاية وحلقة واحدة

السطح الذي يحتاجه API في خط الأنابيب صغير. الوصول إلى API مُضمَّن في الخطط المدفوعة ويُصادَق عليه برمز حامل: أصدر مفتاحًا من لوحة التحكم، وأرسله كـ Authorization: Bearer sr__live_your_api_key. المفتاح نفسه يفتح REST وMCP؛ المرجع الكامل موجود على صفحة المطورين.

graph TD A[نشر يكتمل] --> B["POST /api/v1/reports"] B --> C["GET /api/v1/reports/:id/ready"] C -->|"ready: false"| C C -->|"error.code present"| D[إشارة البنية التحتية، خروج 75] C -->|"ready: true"| E["GET /api/v1/reports/:id"] E --> F{كتلة النقاط ضمن الميزانية?} F -->|نعم| G[exit 0] F -->|لا| H[خروج 1، فشل البناء]

إرسال تقرير هو POST واحد:

bash
JOB_ID=$(curl -sS -X POST https://seoreport.dev/api/v1/reports \
-H "Authorization: Bearer $SEOREPORT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "forceRerun": true}' \
| jq -r '.report.jobId')

شيئين حول ذلك الجسد في CI تحديدًا.

forceRerun موجود لأن API يعيد استخدام لقطة موجودة عندما تكون متاحة — معقول لشخص ينقر زرًا، خطأ في بوابة النشر، التي ستقيم الإصدار السابق خلاف ذلك. الرد يخبرك بما حدث في submission.reusedSnapshot. الج Runs الجديدة القسرية هي ميزة لحساب مدفوع؛ مفتاح بدون ذلك الامتياز يتلقى 403 يذكر السبب بدلاً من إرجاع بيانات قديمة بصمت.

يُستنتج نطاق التدقيق من مسار URL. يقوم أصل بسيط بتدقيق كامل للموقع؛ يُدقق URL مع مسار في عزلة تلك الصفحة. لذلك يمكن أن يحدّ البايبلاين الصفحة الرئيسية في كل نشر ويضيف المسار المحدد الذي لمس تغيّرًا، دون أي معلمة إضافية.

ثم استفتاء. GET /api/v1/reports/:id/ready هو نقطة النهاية الاقتصادية للحالة — تُرجع ready، status، stage، pollAfterMs، وعندما يفشل تشغيل، كائن error:

bash
for _ in $(seq 1 60); do
READY=$(curl -sS -H "Authorization: Bearer $SEOREPORT_API_KEY" \
"https://seoreport.dev/api/v1/reports/$JOB_ID/ready")
CODE=$(echo "$READY" | jq -r '.error.code // empty')
if [ -n "$CODE" ]; then
echo "audit did not complete: $CODE"
exit 75
fi
[ "$(echo "$READY" | jq -r '.ready')" = "true" ] && break
sleep 5
done

هذا exit 75 مقصود، وهو الجزء الذي تُخطئ فيه معظم التكاملات.

تمييز الانحدار عن تشغيل لم يحدث أبدًا

يحمل error.code سببًا قابلًا للقراءة الآلية وretryable بوليان. يُوضع علامة على DNS_FAILURE، CRAWLER_BLOCKED، REDIRECT_LOOP، TLS_ERROR، NO_CONTENT، وSTALE_ENGINE_VERSION كغير قابل لإعادة المحاولة، لأن إعادة المحاولة تُنتج الإجابة المتطابقة. يصف معظم تلك القائمة حالة على الموقع، وعدة مدخلات — حلقة إعادة توجيه، خطأ TLS، قاعدة بوت تُحظر الآن الزواحف — هي عيوب نشر حقيقية تستحق فشل البناء بسببها. الرموز خارج ذلك المجموع transient وتستحق محاولة أخرى.

يُعطل البوابة التي تُدمج "انحدر الموقع" و"لم يتم تشغيل التدقيق" في نفس البناء الأحمر خلال شهر واحد. احتفظ بهم منفصلين في رموز الخروج الخاصة بك: 1 لقرار طلبت البوابة فرضه، 75 — الـ EX_TEMPFAIL التقليدي — لتشغيل لم يُنتج أي قرار على الإطلاق. يمكن تكوين معظم أنظمة CI لإعادة المحاولة للثانية وتوجيه إنسان للثانية الأولى.

قراءة كتلة الدرجات

بمجرد أن يكون ready صحيحًا، تُرجع GET /api/v1/reports/:id كائن التقرير. كتلة score هي الجزء الذي تقرأه البوابة:

bash
REPORT=$(curl -sS -H "Authorization: Bearer $SEOREPORT_API_KEY" \
"https://seoreport.dev/api/v1/reports/$JOB_ID")
echo "$REPORT" | jq '.report.score
| {overall, totalChecks, passedChecks, failedChecks,
warnChecks, inconclusiveChecks, failingCriticalChecks}'

تحمل ثلاثة من تلك الحقول معظم الإشارة.

failingCriticalChecks هو عدد الفشل الذي تصنفه المحرك كحرجة — تلك القادرة على إزالة الصفحات من الفهرس أو إخفاء المحتوى من الزاحف بالكامل. للبوابة الأولى، هذا هو الرقم الوحيد الذي تحتاجه، و> 0 هو عتبة دفاعية في اليوم الأول.

overall هو الدرجة المركبة، مفيدة كقفل: احفظ قيمة النشر السابق وفشل عندما ينخفض الجديد بأكثر من التحمّل الذي تختاره. هذا يلتقط التآكل البطيء الذي لا يحدده أي فحص واحد.

domainScores يقسم الدرجة حسب seo، ai، performance، security، وbrand، كل منها مع pass، fail، وwarn عدّات خاصة به. تُسمح أرضيات لكل نطاق لفرق مختلفة بامتلاك ميزانيات مختلفة — الدرجة الأمنية هي بوابة ذات معنى لمن يملك تكوين الحافة، مستقلًا عن أي شيء يقدمه فريق المحتوى.

inconclusiveChecks تستحق قاعدة خاصة بها: لا تُحدّد عليها أبدًا. يُبلغ الفحص بأنه غير حاسم عندما لا يستطيع المحرك الوصول إلى حكم دفاعي، ومعاملة ذلك كفشل تُدرّب الجميع على تجاهل البوابة.

كتلة النقاط جزء من ملخص التقرير، لذا يمكن لبوابة البناء قراءتها دون جلب النتائج الكاملة. عندما تريد الحمولة الكاملة للأرشفة، يُعيد GET /api/v1/reports/:id/result النتائج الكاملة، ويُعيد GET /api/v1/reports/:id/download?format=json نفس الكائن كقطعة قابلة للتنزيل — يستحق إرفاقه بالبناء حتى يكون الفرق بين نشرين قابلًا للفحص لاحقًا.

توصيله في سير عمل

لا شيء أعلاه هو محدد لمزود CI. في GitHub Actions تكون البوابة بأكملها خطوة واحدة تستدعي السكربت الذي لديك بالفعل:

yaml
- name: SEO audit gate
env:
SEOREPORT_API_KEY: ${{ secrets.SEOREPORT_API_KEY }}
AUDIT_URL: https://example.com
run: ./scripts/seo-gate.sh

حيث يُقدّم seo-gate.sh، يُجري الاستطلاع، وينتهي بالقرار:

bash
CRITICAL=$(echo "$REPORT" | jq -r '.report.score.failingCriticalChecks // 0')
SECURITY=$(echo "$REPORT" | jq -r \
'.report.score.domainScores[] | select(.domain == "security") | .score')
if [ "$CRITICAL" -gt 0 ]; then
echo "::error::$CRITICAL critical checks failing"
exit 1
fi
echo "clean — security domain at $SECURITY"

شغله بعد انتهاء النشر بدلاً من بيئة معاينة. عادةً ما تكون معاينة URL خلف مصادقة أساسية أو تحدٍ بوت، وتقرير تدقيق لا يمكنه جلب الصفحة يُبلغ CRAWLER_BLOCKED بدلاً من النقطة. النشر بعد ذلك على الأصل الحقيقي هو أبسط وأقرب إلى ما يختبره الزاحف.

شكلان متجاوران يستحقان المعرفة. إذا كانت تنسيقك بالفعل على منصة تجريف، فإن شخصية Apify تُشغّل نفس المحرك وفق جدول دون أي من هذه اللصق. وللأجهزة، نفس مفتاح الحامل يُوثّق اتصال MCP عند https://seoreport.dev/mcp، حيث تُعلن أدوات التقرير على connect — يمكن لوكيل يحقق في انخفاض حركة المرور تشغيل التدقيق وقراءة النتائج بنفسه، وهو موثق بجانب سطح REST على صفحة المطورين.

ما لا تغطيه البوابة

تُجيب بوابة النشر على سؤال واحد: هل أدخل هذا الإصدار رجعة. هي صامتة عن كل ما يتغير دون نشر — شهادة تنتهي صلاحيّتها، تكوين CDN مُحرّر في لوحة القيادة، سكربت طرف ثالث يبدأ حظر العرض، أو هجرة منافس تغير ما يتصادم مع اسمك الأساسي. المراقبة حسب النطاق هي التكملة الدائمة للبوابة: مراقبة SEO API تعيد تدقيق نطاق مسجّل كل أسبوع بنفس الحساب والمفتاح.

ابدأ بالنسخة الضيقة. نقطة نهاية واحدة، حقل واحد، failingCriticalChecks > 0، و exit 75 صادق عندما لا يمكن تشغيل التدقيق على الإطلاق. بوابة تُطلق مرتين في السنة وتُعتمد في كلا المرة تُستحق أكثر من واحدة شاملة يتعلم الجميع تخطيها.

احصل على التشخيص الكامل لموقعك

تقرير مدعوم بالأدلة وخطة عمل مرتبة حسب الأولوية، ضمن خطة بأرصدة شهرية.