لا لوحات بيانات في LaRecipe، ولا يخزّن أي حركة زيارات. بل يغذّي الأدوات التي تستخدمها أصلًا. لتضيف أداة، اذكرها تحت integrations.analytics في مدخل المجموعة في config/larecipe.php، فيطبع LaRecipe وسوم السكربت الخاصة بها في رأس كل صفحة من المجموعة:
'sets' => [
'docs' => [
// route, source and access as usual
'integrations' => ['analytics' => [
'plausible' => ['domain' => 'docs.acme.dev'],
]],
],
],وسوم السكربت ترى القرّاء الذين تشغّل متصفحاتهم JavaScript. أما الوكلاء فلا يشغّلون سكربت التحليلات أبدًا، لذا يطلق LaRecipe أيضًا حدث Laravel لكل صفحة ونسخة Markdown و llms.txt ومهارة واستدعاء MCP يقدّمه. استمع إلى هذه الأحداث لترى كل حركة الزيارات لديك.
يشغّل هذا الموقع GA4: يضبط ملف config/larecipe.php الخاص به المفتاح ga4 تحت integrations.analytics في مجموعة docs.
تكاملات التحليلات
| الأداة | المفاتيح | ملاحظات |
|---|---|---|
ga4 |
measurementId |
G- يليه من 4 إلى 20 حرفًا لاتينيًا كبيرًا أو رقمًا. يحمّل gtag.js من Google. |
plausible |
domain، src |
يمكن أن يذكر domain عدة نطاقات، مفصولة بفواصل. القيمة الافتراضية لـ src هي https://plausible.io/js/script.js؛ والمضيف الآخر من الإعدادات فقط. |
fathom |
siteId، src |
siteId من 4 إلى 20 حرفًا لاتينيًا كبيرًا أو رقمًا. القيمة الافتراضية لـ src هي https://cdn.usefathom.com/script.js؛ والمضيف الآخر من الإعدادات فقط. |
posthog |
apiKey، host |
يبدأ apiKey بـ phc_. القيمة الافتراضية لـ host هي https://us.i.posthog.com؛ والمضيف الخاص بك من الإعدادات فقط. |
custom |
src، defer، async، attributes |
أي سكربت، بعنوان https. يُؤجَّل تحميله ما لم تضبط defer على false. ولا يقبل attributes إلا سمات data-*. |
يفحص LaRecipe كل قيمة مقابل الشكل الذي يستخدمه مزوّدها قبل أن تصل إلى الصفحة، ويُسقط الوسم الذي لا تناسب قيمه. يجب أن تكون مصادر السكربتات عناوين https، ولا يمكن لأي إعداد أن يضيف كودًا مضمّنًا إلى الصفحة. وحين يضبط تطبيقك قيمة nonce لسياسة أمان المحتوى (Content Security Policy) عبر LaRecipe::useCspNonce()، يحملها كل وسم.
ويجوز لمجموعة المستودع أيضًا أن تعرّف التكاملات في ملف larecipe.json الخاص بها، بالمفاتيح نفسها.
config/larecipe.php أم larecipe.json: أيهما يُعتمد
تعمل هذه السكربتات ضمن جلسة كل قارئ، لذا يهمّ من أين تأتي:
config/larecipe.phpيُعتمد لكل مجموعة، ويتقدّم علىlarecipe.jsonفي كل أداة.larecipe.jsonيُعتمد لمجموعة المستودع فقط، لأن ملف تعريفها يُراجع مع الكود. أما ملفlarecipe.jsonلمجموعة قاعدة البيانات فيمكن تغييره من لوحة الإدارة وعبر MCP، لذا تتجاهل مجموعة قاعدة البيانات التكاملات فيه، ويحذّر منهاlarecipe:validateتحتmanifest.integrations.- المضيف المستضاف ذاتيًا أو الخادم الوسيط لا يُعتمد إلا من
config/larecipe.php: أيsrcفي Plausible و Fathom، وhostفي PostHog. ومنlarecipe.jsonلا تُحمَّل إلا من مضيفيها الرسميين (plausible.ioوcdn.usefathom.comومضيفي PostHogusوeuوapp)، عبرhttps.
التكامل نفسه في larecipe.json:
{
"integrations": {
"analytics": {
"plausible": { "domain": "docs.acme.dev" }
}
}
}يبلّغ php artisan larecipe:validate عن قيم larecipe.json التي تخالف المخطط بوصفها أخطاء manifest.schema.
تقييم الصفحات
تنتهي كل صفحة بالسؤال «هل كانت هذه الصفحة مفيدة؟»، مع «نعم» و «لا»، وتعليق اختياري يصل إلى 2,000 حرف. تحتاج هذه الأداة إلى JavaScript. ولا يخزّن LaRecipe أي إجابة. بل إن كل إجابة:
- تطلق
FeedbackSubmittedمع الصفحة والإجابة والتعليق ونوع الطلب، وsourceمضبوط علىreader. وتطلق أداة MCPsubmit_feedbackالحدث نفسه وsourceمضبوط علىagent، فتصل تقييمات الوكلاء بالطريقة نفسها. - تُبلَّغ إلى أداة التحليلات، حين يكون هناك تكامل مضبوط. تحصل التحليلات على الصفحة والإصدار واللغة والإجابة والمصدر. أما التعليق فلا يذهب إلا إلى المستمعين في Laravel لديك.
أوقف هذه الأداة بضبط feedback.enabled على false في config/larecipe.php. فيزيل ذلك الأداة ومسارها وأداة MCP submit_feedback.
مسار التقييم، وما تستقبله كل أداة تحليلات
التصويت الذي يُترك من دون الضغط على «إرسال» يُرسل مع ذلك حين ينتقل القارئ. وكل إجابة تُرسل إلى مسار التقييم الخاص بالمجموعة:
POST /_feedback| Method | POST |
|---|---|
| URI | /_feedback |
| Middleware | web, throttle |
يعمل المسار ضمن مجموعة الوسائط (middleware) الخاصة بالمجموعة (web افتراضيًا)، فتنطبق الجلسة والحماية من CSRF لديك، وهو محدود لكل مستخدم أو عنوان IP بحسب feedback.rate_limit (20 في الدقيقة افتراضيًا). ويجيب بـ 204. والتقييم على صفحة لا يحق للمرسل رؤيتها يعيد 404، مثل الصفحة نفسها.
تطلق الأداة حدث المتصفح larecipe:feedback، وتمرّره وسوم LaRecipe: حدث larecipe_feedback في GA4 و PostHog، وحدث Docs Feedback في Plausible، و docs feedback: helpful أو docs feedback: not helpful في Fathom.
تقييم الإجابات
حين يكون Ask AI مفعّلًا، تحمل كل إجابة مكتملة زرّي إعجاب وعدم إعجاب. يُرسل التصويت إلى مسار التقييم نفسه مع السؤال الذي كانت الإجابة له، فيصل FeedbackSubmitted و source مضبوط على ask و question معبّأ، والصفحة هي التي سأل منها القارئ. وتحصل التحليلات لديك على حدث larecipe:feedback نفسه، بالمصدر ask. ويتبع الزرّان feedback.enabled أيضًا.
الأحداث
يطلق LaRecipe حدث Laravel لكل نوع من الطلبات التي يقدّمها. وهي موجودة في LaRecipe\Domains\Delivery\Events.
| الحدث | يُطلق حين |
|---|---|
PageViewed |
تُقدَّم صفحة بصيغة HTML، أو Markdown، أو JSON للتنقل من جهة المتصفح |
MarkdownServed |
تُقدَّم نسخة Markdown لصفحة (عنوان .md أو Accept: text/markdown)، إلى جانب PageViewed |
LlmsTxtServed |
يُقدَّم llms.txt أو llms-full.txt |
SkillServed |
يُقدَّم skill.md، أو ملف مهارة مكتوب يدويًا، أو /.well-known/agent-skills/index.json |
McpToolCalled |
تُستدعى أداة MCP، على نقطة النهاية عبر الويب أو على الخادم المحلي |
SearchPerformed |
يجري بحث على الخادم (أداة MCP search_docs، أو Ask AI، أو /ask، أو نقطة النهاية /_search)، أو تبلّغ اللوحة عن عمليات بحث أجابت عنها في المتصفح |
AskAiAnswered |
ينهي Ask AI إجابة |
FeedbackSubmitted |
يرسل قارئ أو وكيل تقييمًا لصفحة، أو يقيّم قارئ إجابة من Ask AI |
كل واحد منها يحمل kind: إما human أو crawler أو agent، ويُحدَّد من وكيل المستخدم في الطلب ومن كونه يطلب Markdown أم لا. ولا يُستخدم هذا النوع إلا في الأحداث؛ ولا يغيّر أبدًا ما يقدّمه LaRecipe. وتجد في مرجع الأحداث القواعد الدقيقة وحقول كل حدث.
استمع إليها كأي حدث Laravel، وأرسلها إلى حيث تشاء: واجهة برمجة أداة التحليلات من جهة الخادم، أو صف في جدول خاص بك، أو سجل.
حقول الحدث PageViewed، مقروءة من هذا التطبيق
LaRecipe\Domains\Delivery\Events\PageViewed| Property | Type |
|---|---|
kind | string |
userAgent | ?string |
set | string |
page | LaRecipe\Domains\Content\DTOs\PageRef |
format | string |
| Listener | Runs |
|---|
قيمة format هي html أو markdown أو json، و page كائن PageRef فيه المجموعة والإصدار واللغة والمسار. وكل الأحداث تحمل مجموعة التوثيق، ما عدا SkillServed لفهرس المهارات الذي يجمع المجموعات كلها. ويوجد PageRendered في مساحة الأسماء نفسها، لكنه يخص التصيير لا القرّاء، ولا يحمل kind.
مستمع يمرّر حركة الوكلاء وزواحف الويب
يرسل هذا المستمع مشاهدات الصفحات من الوكلاء وزواحف الويب، وهي الحركة التي لا يراها سكربت التحليلات أبدًا، إلى السجلات لديك:
<?php
namespace App\Listeners;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;
use LaRecipe\Domains\Delivery\Events\PageViewed;
class ForwardDocsTraffic implements ShouldQueue
{
public function handle(PageViewed $event): void
{
// People already reach your client-side analytics. Skip LaRecipe's own export and doctor runs too.
if ($event->kind === 'human' || str_starts_with((string) $event->userAgent, 'LaRecipe-')) {
return;
}
Log::info('Docs page viewed', [
'set' => $event->set,
'version' => $event->page->version,
'locale' => $event->page->locale,
'path' => $event->page->path,
'format' => $event->format,
'kind' => $event->kind,
'user_agent' => $event->userAgent,
]);
}
}- يكتشف Laravel المستمعين في
app/Listenersمن تلقاء نفسه. ولتسجّله يدويًا، أضفEvent::listen(PageViewed::class, ForwardDocsTraffic::class)إلىboot()في مزوّد خدمة. - ينقل
ShouldQueueالعمل إلى الطابور لديك، فلا تنتظر الصفحة أداة التحليلات أبدًا. شغّل عامل طوابير، أو احذف الواجهة ليعمل المستمع أثناء الطلب. - يطلب
larecipe:exportوlarecipe:doctorالصفحات عبر تطبيقك باسمَيLaRecipe-Export/3 (static export)وLaRecipe-Doctor/1.0، وتطلق هذه الطلبات أحداثًا أيضًا. والفحص علىLaRecipe-أعلاه يستبعدها.
التالي
- البحث: اعثر بالحدث
SearchPerformedعلى الأسئلة التي لا يجيب عنها توثيقك بعد. - مرجع الأحداث: كل حدث وحقوله وكيف يُحدَّد نوع الطلب.
- واجهات الوكلاء: الملفات التي يقرؤها الوكلاء، والأحداث التي يطلقها كل منها.