Firebase — نموذج البيانات وخطة التنفيذ
قرارات المالك (2026-07-10): دخول بريد/كلمة مرور؛ التعليقات تُنشر بعد موافقة المشرف (نظام فلترة سبام لاحقًا)؛ الترشيحات v1 فقط (زر ترشيح + قسم اختيارات القراء). الاستضافة تبقى على GitHub Pages — خدمات Firebase تعمل من المتصفح ولا تشترط استضافتهم.
المجموعات (Collections)
users/{uid}
displayName string (2-40 حرفًا — يظهر بجانب التعليقات)
createdAt timestamp
users/{uid}/library/{bookSlug} ← المفضلة المتزامنة (My Library)
title, author, cover_url, isbn, google_id, page_count, added_at
books/{bookSlug}/comments/{commentId} ← التعليقات (بإشراف مسبق)
uid string (= كاتب التعليق، تفرضه القواعد)
name string (اسم العرض وقت الكتابة)
text string (2-1000 حرف، تفرضه القواعد)
createdAt timestamp (وقت الخادم، تفرضه القواعد)
approved bool (يُنشأ false دائمًا؛ لا يقلبه إلا المشرف)
books/{bookSlug}/recs/{uid} ← أصوات الترشيح v1
createdAt timestamp
(معرّف الوثيقة = uid ⇒ صوت واحد لكل مستخدم بنيويًا)
قرارات تصميم مفصلية
- قواعد الأمان هي خط الدفاع الوحيد (لا خادم وسيط) — الملف
firestore.rulesهو المصدر الرسمي، ونسخة اللوحة يجب أن تطابقه دائمًا. - قراءة التعليقات العامة تمر حصرًا عبر استعلام يتضمن
where("approved","==",true)— أي استعلام بدونه ترفضه القواعد بالكامل. - صفحة إشراف بسيطة
/admin/comments/(المرحلة 3): يراها حساب المشرف فقط (uid مثبت في القواعد)، تعرض المعلّق منها بأزرار موافقة/حذف. - عدّادات الترشيح عبر استعلامات
count()المدمجة (قراءة واحدة لكل 1000 وثيقة) — لا قراءة للوثائق نفسها. - ترحيل المفضلة: عند أول تسجيل دخول تُدمج مكتبة localStorage الحالية في Firestore ثم يبقى localStorage مسار الزائر غير المسجل كما هو.
- التحميل كسول دائمًا (التعليقات عند فتح قسمها) — حصة Spark المجانية 50 ألف قراءة/يوم وهي الحاكم الحقيقي للتصميم.
خطوات لوحة Firebase (يدوية — يفعلها المالك مرة واحدة)
- https://console.firebase.google.com ← Add project (اسم مثل
bookhub-site، وGoogle Analytics اختياري — عطّله للتبسيط). - Authentication ← Get started ← Sign-in method ← Email/Password ← Enable.
- Firestore Database ← Create database ← Production mode (أقرب
Region لجمهورك —
eur3مناسب لأوروبا/شمال أفريقيا). ثم تبويب Rules: الصق محتوىfirestore.rulesكاملًا وانشر. - أنشئ حسابك الشخصي أولًا (من صفحة الدخول بعد بناء المرحلة 1، أو من
Authentication ← Add user)، ثم انسخ الـUID من Authentication ← Users
وضعه مكان
REPLACE_WITH_ADMIN_UIDفي القواعد (الملف واللوحة معًا) وأعد النشر. - Project settings (⚙) ← Your apps ← Web app (</>) ← سجّل تطبيقًا
باسم
bookhub-web(بدون Hosting) ← انسخ كائنfirebaseConfigوأرسله لي (قيمه عامة بطبيعتها — تظهر في كود المتصفح — والحماية الفعلية في القواعد، لكن لا ترسل أبدًا أي “service account key”). - (يُوصى به، بعد استقرار كل شيء) App Check بمزود reCAPTCHA v3 — يقلل السبام الآلي قبل نظام الفلترة الذي ستبنيه.
المراحل
- 0 ✅ الملف والقواعد. ⚠️ أعد لصق القواعد في اللوحة (أُضيفت قاعدة قراءة جماعية للمشرف في المرحلة 3) + استبدل REPLACE_WITH_ADMIN_UID.
- 1 ✅ واجهة الدخول في الهيدر المشترك (بريد/كلمة مرور: تسجيل، دخول،
استعادة كلمة مرور، قائمة حساب) — تبدأ فور وصول
firebaseConfig. - 2 ✅ مزامنة المفضلة (+ دمج localStorage عند أول دخول).
- 3 ✅ التعليقات على صفحة الملخص + صفحة الإشراف /admin/comments/ (أول تحميل لقائمة الإشراف قد يطلب إنشاء فهرس collection-group — رابط الإنشاء بنقرة واحدة يظهر في كونسول المتصفح).
- 4 ✅ زر الترشيح (صوت/تراجع + عدّاد حي). ⏳ قسم “اختيارات القراء” في الرئيسية مؤجل حتى تتراكم أصوات فعلية (يتطلب تجميعًا ليليًا عبر Render/Admin SDK — لا معنى له وقائمة الأصوات فارغة).
- مؤجل: ترشيحات مخصصة v2 (تقاطع مفضلات عبر Render/Action ليلي)، App Check، نظام فلترة السبام (سيبنيه المالك)، هجرة الاستضافة (غير موصى بها — راجع ROADMAP في bookhub-api).