المفتاح
CROSS-DEPARTMENT-KANBAN PUBLIC / 2026

بعض التفاصيل محجوبة. إن كان لديك مفتاح وصول، فبإمكانك مطالعة النسخة الكاملة.

شركة لتأجير معدّات الطاقة الجديدة ومعدّات البناء

لوحة كانبان داخلية تُدير الطلبات العابرة بين الأقسام

حوّلتُ الطلبات بين الأقسام، التي كانت تدور على جداول Google وApps Script، إلى لوحة كانبان لحظية تعمل على حافّة Cloudflare. والطلبات ليست في جدول منفصل، بل تتشارك النموذج نفسه مع المهامّ. 17 يومًا، وحدي، حتى النشر.

لوحة كانبان داخلية تُدير الطلبات العابرة بين الأقسام

نظرة عامة

كانت الطلبات بين أقسام العميل تدور في الأصل على جداول Google وApps Script. فمَن طلب من مَن، وإلى أين وصل العمل، كان يُحفَظ بورقة مشتركة واحدة وبتذكيرات تُرسَل يدويًّا. وVulcan هو تحويل هذا المسار إلى نظام كانبان.

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

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

حجم الكود 34 ألف سطر
حالات الاختبار أكثر من 470
حجم الاستعمال نحو 100 موظّف / أكثر من 10 أقسام
مدّة التطوير 17 يومًا

البنية

الواجهة تطبيق صفحة واحدة على SvelteKit، وقد أوقفتُ التصيير من الخادم في التطبيق كلّه. فاللوحة شاشة كثيرة التفاعل ولا مطلب لها في تحسين محرّكات البحث، فلا يعود عليها التصيير من الخادم بشيء، بينما يُلزمها بمراعاة مسارَي تصيير في كلّ عملية.

لا تمرّ البيانات إلا عبر نقاط BFF الخاصّة بهذا التطبيق وحده، وعددها 42. وهذه النقاط مرتبطة بقاعدة البيانات مباشرةً على الـ Worker، فلا يحمل المتصفّح مقبضًا لقاعدة البيانات أبدًا. والوصول إلى البيانات مجموع في طبقة استعلامات Drizzle مشتركة، فلا يُكتب SQL في جانب التطبيق.

بيئة التشغيل كلّها على حافّة Cloudflare: الـ Worker يحمل التطبيق، وD1 للبيانات، وR2 للمرفقات، وKV للإعدادات الشخصية، وDurable Object لمزامنة الحالة. وتسجيل الدخول بـ Google OAuth، والجلسة مشتركة مع تطبيقَين داخليَّين آخرَين.

تكوين النظام: تطبيق الصفحة الواحدة في المتصفّح، ونقاط BFF على الـ Worker، وعلاقتها بأربعة أنواع من موارد الحافّة: D1 وR2 وKV وDurable Object
تكوين النظام: تطبيق الصفحة الواحدة في المتصفّح، ونقاط BFF على الـ Worker، وعلاقتها بأربعة أنواع من موارد الحافّة: D1 وR2 وKV وDurable Object

المواضع الصعبة تقنيًّا

المزامنة بين عدّة أشخاص: بثّ إشارات الإبطال وحدها

إن عدّل أحدهم مهمّة، أردتُ للوحات الآخرين أن تتبعه. ومع ذلك لم أُدخل CRDT. فالـ Durable Object لا يتعدّى كونه مُرحِّلًا للبثّ، ولا يمرّر إلا بادئات مفاتيح الاستعلام التي بطلت. أمّا العميل الذي يستقبلها فيُنهي صلاحية ما يقابلها في مخزنه ويجلبه من جديد. والحقيقة الوحيدة للبيانات تبقى دائمًا في جانب قاعدة البيانات.

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

وفي مقابل هذا الحسم لم أضطرّ إلى تغيير حرف واحد من التحكّم التفاؤلي بالتزامن ولا من منطق الترتيب، ولم أضطرّ إلى وضع أيّ بيانات عمل داخل الـ Durable Object. والاتصالات تستعمل واجهة الإسبات، ونبضات الإبقاء تردّها بيئة التشغيل تلقائيًّا فلا تستيقظ النسخة. وعند انقطاع الاتصال يُتراجَع إلى الاستطلاع الدوري.

LIVE تفاعلي — جرّبه
مقابلة بين شاشتين: تُعدَّل المهمّة في اليسار، ويُعرض في اليمين محتوى الإشارة كما وصل فعلًا، ثم عملية الجلب التي تليها

حقن Durable Object في نقطة دخول يكتبها إطار العمل فوقك

محوّل Cloudflare يعيد كتابة ملفّ دخول الـ Worker مع كلّ بناء، فلا يمكن ترك تصدير Durable Object مكتوبًا بخطّ اليد هناك. لذلك يزيح برنامجُ البناء الناتجَ جانبًا بعد الترجمة، ويولّد في موضعه نقطةَ دخول غلافية: تمرّر الطلبات العادية إلى إطار العمل، ولا تعترض إلا طلبات ترقية الاتصال، وتصدّر معها صنف الـ Durable Object.

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

التحكّم التفاؤلي بالتزامن والفهرس الكسري

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

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

اشتقاق حالة المهمّة الأمّ اشتقاقًا تعاوديًّا

حالة المهمّة الأمّ تُحسب من المهامّ الأبناء ولا تُحفَظ على حدة. فإن تغيّر ابنٌ أُعيد الحساب من أمّه صعودًا طبقةً طبقة، وتوقّف عند أوّل طبقة لا تتغيّر نتيجتها — لأن كلّ اشتقاق فوقها لا يعتمد إلا على تلك القيمة التي لم تتغيّر. ويُحتفَظ إلى جانب ذلك بمجموعة المزارات منعًا للدوران.

لا فهرس بحث كامل النصّ في اللغة اليابانية

البحث بمطابقة جزئية وترتيب بالنقاط في جانب التطبيق، دون فهرس البحث الكامل في SQLite. فالمُقطِّع الافتراضي لا يقوى على تقطيع اليابانية، وفهرس الثلاثيات يُسقِط الكلمات ذوات المحرفين مثل「予約」و「会議」. ولأن نطاق البحث محصور في قسم الباحث نفسه، فكلفة المسح في حدود المقبول.

الشاشة الرئيسة للوحة: أعمدة مقسومة بحسب الحالة، وإعادة ترتيب بالسحب. ومن قائمة الزرّ الأيمن يمكن تحرير حقل مفرد مباشرةً
الشاشة الرئيسة للوحة: أعمدة مقسومة بحسب الحالة، وإعادة ترتيب بالسحب. ومن قائمة الزرّ الأيمن يمكن تحرير حقل مفرد مباشرةً
قائمة
قائمة
خطّ زمني
خطّ زمني

طريقة عمل أصلها الذكاء الاصطناعي

استغرق هذا المشروع 17 يومًا من أوّل التزام إلى النشر في الإنتاج. ومن التزاماته الـ400 هناك 223 تحمل توقيع تأليف مشترك من الذكاء الاصطناعي. وطريقة العمل أن أعامل وكيل الذكاء الاصطناعي شريكًا في التصميم: أتولّى أنا صياغة المسألة والمفاضلة، ويقدّم هو التنفيذ، ثم أراجعه أنا وأقرّر أيبقى أم لا.

والذي يُبقي هذه السرعة ممكنة هو تدوين القرارات. ففي المستودع أربع وثائق موجَّهة للوكيل، تبلغ معًا ما يزيد على 2,000 سطر. وليس المكتوب فيها بنيةَ الكود، بل لماذا اتُّخذ كلُّ قرار على وجهه، وأيّ الطرق جُرِّبت ورُفضت من قبل.

لماذا حُذف جدول التقويم، ولماذا لا يُفرد للطلبات جدول خاصّ، ولماذا لا يُستعمل فهرس النصّ الكامل في البحث. كلّها مكتوبة مع ثمنها في الوثائق وفي صدر ملفّات الترحيل. فمن يأتي بعدي ليعدّل هنا يقرأ أسبابَ القرار، ولا يحتاج إلى أن يخمّنها من جديد.

وتثبّت الوثائق في الوقت نفسه مواضعَ يسهل انزلاقها: أن تُوضع تعريفات الأنواع المعدودة في ملفّ واحد لا غير، وألّا تُحرَّك مفاتيح الاستعلام في الكود حين تتغيّر عبارات الشاشة، وألّا تُدمج حقول التواريخ المختلفة في معناها. ولكلٍّ منها اختبارٌ يحرسه.