Firebase Supabase MongoDB LocalStorage REST API

الربط السحابي الشامل ☁️

تعلّم ربط تطبيقاتك بخمس أنظمة تخزين مختلفة — من المتصفح حتى السحابة — مع أكواد كاملة قابلة للنسخ مباشرة.

Firebase Supabase MongoDB Atlas LocalStorage REST API
🔥

Firebase (Google)

NoSQL Cloud Database — الأسرع للبدء، مثالي للمشاريع المتوسطة والكبيرة

خطوات الإعداد الكاملة

1. إنشاء المشروع

في console.firebase.google.com أنشئ مشروعاً جديداً واحصل على ملف التكوين.

2. تثبيت الـ SDK

عبر CDN أو npm install firebase حسب نوع مشروعك.

3. التهيئة

انسخ firebaseConfig من لوحة المشروع والصقها في كودك.

firebase-config.js
// ─── تثبيت عبر CDN (في HTML) ─── // <script type="module"> ... </script> import { initializeApp } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js"; import { getFirestore } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-firestore.js"; import { getAuth } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-auth.js"; import { getStorage } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-storage.js"; // ─── معلومات مشروعك (من Firebase Console) ─── const firebaseConfig = { apiKey: "AIzaSy...", authDomain: "myapp.firebaseapp.com", projectId: "myapp-12345", storageBucket: "myapp-12345.appspot.com", messagingSenderId: "123456789", appId: "1:123456789:web:abcdef" }; // ─── تهيئة Firebase ─── const app = initializeApp(firebaseConfig); const db = getFirestore(app); // Firestore Database const auth = getAuth(app); // Authentication const storage = getStorage(app); // File Storage export { db, auth, storage };
⚠️ لا تضع الـ apiKey في مستودع GitHub عام. استخدم Environment Variables في مشاريع الـ Production.

نظام المصادقة الكامل

auth.js — تسجيل / دخول / مراقبة
import { auth } from "./firebase-config.js"; import { createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut, onAuthStateChanged, updateProfile, sendPasswordResetEmail, GoogleAuthProvider, signInWithPopup } from "firebase/auth"; // ─── 1. إنشاء حساب جديد ─── async function register(email, password, displayName) { try { const cred = await createUserWithEmailAndPassword(auth, email, password); // تحديث الاسم فور الإنشاء await updateProfile(cred.user, { displayName }); console.log("✅ تم إنشاء الحساب:", cred.user.uid); return cred.user; } catch (err) { const msgs = { 'auth/email-already-in-use': "الإيميل مستخدم بالفعل", 'auth/weak-password': "كلمة المرور ضعيفة جداً (6+ أحرف)", 'auth/invalid-email': "صيغة الإيميل غير صحيحة", }; throw new Error(msgs[err.code] || err.message); } } // ─── 2. تسجيل الدخول ─── async function login(email, password) { try { const cred = await signInWithEmailAndPassword(auth, email, password); window.location.href = "dashboard.html"; // redirect بعد الدخول } catch (err) { const msgs = { 'auth/user-not-found': "لا يوجد حساب بهذا الإيميل", 'auth/wrong-password': "كلمة المرور غير صحيحة", 'auth/too-many-requests': "محاولات كثيرة، انتظر قليلاً", }; throw new Error(msgs[err.code] || err.message); } } // ─── 3. الدخول بـ Google OAuth ─── async function loginWithGoogle() { const provider = new GoogleAuthProvider(); const cred = await signInWithPopup(auth, provider); console.log("مسجل كـ:", cred.user.email); } // ─── 4. مراقب الحالة (أهم دالة في Auth) ─── onAuthStateChanged(auth, (user) => { if (user) { console.log(`مرحباً ${user.displayName} (${user.uid})`); loadUserData(user.uid); // جلب بيانات المستخدم من Firestore } else { window.location.href = "login.html"; // redirect لو لم يدخل } }); // ─── 5. تسجيل الخروج وإعادة التعيين ─── const logout = () => signOut(auth); const resetPassword = (email) => sendPasswordResetEmail(auth, email);

Firestore — CRUD كامل

firestore.js — القراءة / الكتابة / الحذف / Real-time
import { db } from "./firebase-config.js"; import { collection, doc, addDoc, setDoc, getDoc, getDocs, updateDoc, deleteDoc, onSnapshot, query, where, orderBy, limit, serverTimestamp, increment } from "firebase/firestore"; const playersRef = collection(db, "players"); // ─── CREATE — إضافة وثيقة (ID تلقائي) ─── async function addPlayer(data) { const docRef = await addDoc(playersRef, { ...data, createdAt: serverTimestamp(), // وقت السيرفر لا العميل score: 0 }); console.log("ID الجديد:", docRef.id); } // CREATE بـ ID محدد (مثلاً UID المستخدم) async function createUserProfile(uid, data) { await setDoc(doc(db, "users", uid), { ...data, createdAt: serverTimestamp() }); } // ─── READ — قراءة وثيقة واحدة ─── async function getPlayer(id) { const snap = await getDoc(doc(db, "players", id)); if (snap.exists()) return { id: snap.id, ...snap.data() }; throw new Error("اللاعب غير موجود"); } // READ — استعلام متقدم مع فلترة وترتيب async function getTopPlayers() { const q = query( playersRef, where("rank", "==", "Gold"), where("score", ">=", 1000), orderBy("score", "desc"), limit(10) ); const snap = await getDocs(q); return snap.docs.map(d => ({ id: d.id, ...d.data() })); } // ─── UPDATE ─── async function updateScore(id, points) { await updateDoc(doc(db, "players", id), { score: increment(points), // زيادة ذرية آمنة lastSeen: serverTimestamp() }); } // ─── DELETE ─── const deletePlayer = (id) => deleteDoc(doc(db, "players", id)); // ─── REAL-TIME LISTENER — يحدّث تلقائياً ─── function watchLeaderboard(onUpdate) { const q = query(playersRef, orderBy("score", "desc"), limit(20)); return onSnapshot(q, (snap) => { const players = snap.docs.map(d => ({ id: d.id, ...d.data() })); onUpdate(players); // يُستدعى كلما تغيرت البيانات }); // ✅ لإيقاف الاستماع: const unsub = watchLeaderboard(...); unsub(); }
🔒 Security Rules: في Firestore، اكتب قواعد تتحقق من auth.uid مثل: allow write: if request.auth.uid == userId;

Realtime Database — البيانات الحية الفورية

import { getDatabase, ref, set, push, onValue, get, remove, update } from "firebase/database"; const rtdb = getDatabase(app); // ─── كتابة بمسار محدد ─── await set(ref(rtdb, `users/${uid}`), { name: "Ahmed", online: true }); // ─── إضافة بـ ID تلقائي (مثل Array) ─── const newRef = await push(ref(rtdb, "messages"), { text: "مرحباً!", time: Date.now() }); // ─── قراءة مرة واحدة ─── const snap = await get(ref(rtdb, `users/${uid}`)); if (snap.exists()) console.log(snap.val()); // ─── مستمع Real-time ─── onValue(ref(rtdb, "game/state"), (snap) => { renderGame(snap.val()); // يُشغَّل فور أي تغيير }); // ─── Presence System (هل المستخدم متصل؟) ─── import { serverTimestamp, onDisconnect } from "firebase/database"; const presRef = ref(rtdb, `presence/${uid}`); await set(presRef, { online: true, lastSeen: serverTimestamp() }); onDisconnect(presRef).set({ online: false, lastSeen: serverTimestamp() });

Firebase Storage — رفع الملفات

import { storage } from "./firebase-config.js"; import { ref as storageRef, uploadBytesResumable, getDownloadURL, deleteObject } from "firebase/storage"; // ─── رفع صورة مع شريط التقدم ─── async function uploadAvatar(uid, file, onProgress) { const ext = file.name.split(".").pop(); const path = `avatars/${uid}.${ext}`; const sRef = storageRef(storage, path); const task = uploadBytesResumable(sRef, file); return new Promise((resolve, reject) => { task.on("state_changed", (snap) => { // أثناء الرفع const pct = (snap.bytesTransferred / snap.totalBytes) * 100; onProgress(Math.round(pct)); }, reject, // عند الخطأ async () => { // بعد الانتهاء const url = await getDownloadURL(task.snapshot.ref); resolve(url); // رابط قابل للنشر } ); }); }

Supabase

PostgreSQL مفتوح المصدر — SQL كامل، RLS قوي، Real-time مدمج

الإعداد والتهيئة

// ─── CDN ─── // <script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script> // ─── أو npm ─── // npm install @supabase/supabase-js import { createClient } from "@supabase/supabase-js"; const SUPABASE_URL = "https://xyzxyz.supabase.co"; const SUPABASE_KEY = "eyJhbGciOi..."; // anon public key export const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
import { supabase } from "./supabase-client.js"; // ─── تسجيل ─── const { data, error } = await supabase.auth.signUp({ email: "ahmed@example.com", password: "SecurePass123", options: { data: { username: "ahmed_gamer" } } // metadata }); if (error) throw error; // ─── دخول ─── const { data: session } = await supabase.auth.signInWithPassword({ email: "ahmed@example.com", password: "SecurePass123" }); // ─── Google OAuth ─── await supabase.auth.signInWithOAuth({ provider: "google" }); // ─── مراقب الحالة ─── supabase.auth.onAuthStateChange((event, session) => { if (session) { loadDashboard(session.user); } else { window.location.href = "login.html"; } }); // ─── المستخدم الحالي ─── const { data: { user } } = await supabase.auth.getUser(); // ─── تسجيل خروج ─── await supabase.auth.signOut();
// ─── SELECT — قراءة بفلترة وترتيب ─── const { data: players } = await supabase .from("players") .select("id, name, score, avatar_url, created_at") .eq("rank", "Gold") // WHERE rank = 'Gold' .gte("score", 1000) // AND score >= 1000 .order("score", { ascending: false }) .limit(10); // SELECT مع JOIN (القوة الحقيقية لـ Supabase) const { data } = await supabase .from("posts") .select("*, profiles(username, avatar), comments(count)"); // ─── INSERT ─── const { data: newPlayer, error } = await supabase .from("players") .insert({ name: "Ahmed", score: 0, rank: "Bronze" }) .select() // يُرجع الصف المُدرج .single(); // نتيجة واحدة لا مصفوفة // ─── UPDATE ─── const { error } = await supabase .from("players") .update({ score: 1500, rank: "Platinum" }) .eq("id", playerId); // ─── UPSERT — Insert أو Update تلقائياً ─── await supabase.from("profiles").upsert({ id: user.id, username: "ahmed", updated_at: new Date() }, { onConflict: "id" }); // ─── DELETE ─── await supabase.from("players").delete().eq("id", playerId); // ─── RPC — استدعاء دالة SQL ─── const { data } = await supabase.rpc("increment_score", { player_id: id, points: 50 });
// ─── الاستماع لتغييرات جدول ─── const channel = supabase .channel("leaderboard-changes") .on("postgres_changes", { event: "*", // INSERT | UPDATE | DELETE | * schema: "public", table: "scores", filter: "game_id=eq.42" // فلتر اختياري }, (payload) => { console.log(payload.eventType, payload.new, payload.old); refreshLeaderboard(); }) .subscribe(); // إيقاف الاستماع await supabase.removeChannel(channel); // ─── Presence — من هو متصل الآن؟ ─── const room = supabase.channel("online-users"); room .on("presence", { event: "sync" }, () => { const online = Object.values(room.presenceState()); renderOnlineUsers(online); }) .subscribe(async (status) => { if (status === "SUBSCRIBED") { await room.track({ user_id: user.id, online_at: new Date() }); } });
🌿

MongoDB Atlas

NoSQL مرن — مثالي مع Node.js/Express وتطبيقات API

💡 MongoDB يعمل عادةً مع Backend (Node.js). لا تتصل به مباشرة من المتصفح لأسباب أمنية — بدلاً من ذلك اصنع API.
server.js — Node.js + MongoDB Atlas
// npm install mongoose express cors dotenv const mongoose = require("mongoose"); const express = require("express"); const app = express(); app.use(express.json()); // ─── الاتصال بـ Atlas ─── await mongoose.connect(process.env.MONGO_URI); console.log("✅ Connected to MongoDB Atlas"); // ─── تعريف Schema ─── const PlayerSchema = new mongoose.Schema({ name: { type: String, required: true, trim: true }, email: { type: String, unique: true, lowercase: true }, score: { type: Number, default: 0, min: 0 }, rank: { type: String, enum: ["Bronze","Silver","Gold","Platinum"] }, createdAt: { type: Date, default: Date.now } }); const Player = mongoose.model("Player", PlayerSchema); // ─── REST API Endpoints ─── // GET /api/players — جلب كل اللاعبين app.get("/api/players", async (req, res) => { try { const players = await Player .find({ score: { $gte: 0 } }) .sort({ score: -1 }) .limit(50) .select("-__v"); // إخفاء حقل __v res.json({ success: true, data: players }); } catch (e) { res.status(500).json({ error: e.message }); } }); // POST /api/players — إضافة لاعب app.post("/api/players", async (req, res) => { try { const player = await Player.create(req.body); res.status(201).json({ success: true, data: player }); } catch (e) { res.status(400).json({ error: e.message }); } }); // PATCH /api/players/:id/score — تحديث النقاط app.patch("/api/players/:id/score", async (req, res) => { const updated = await Player.findByIdAndUpdate( req.params.id, { $inc: { score: req.body.points } }, // $inc يزيد القيمة { new: true } // يُرجع القيمة الجديدة ); res.json(updated); }); app.listen(3000);
💾

LocalStorage & IndexedDB

تخزين المتصفح — بدون إنترنت، سريع جداً، مثالي للإعدادات والبيانات المؤقتة

// ─── LocalStorage — نص فقط (5MB) ─── // الكتابة — يجب تحويل Objects لـ JSON localStorage.setItem("theme", "dark"); localStorage.setItem("user", JSON.stringify({ name: "Ahmed", level: 42, settings: { sound: true } })); // القراءة — يجب تحويل JSON لـ Object const theme = localStorage.getItem("theme"); // "dark" const userRaw = localStorage.getItem("user"); const user = userRaw ? JSON.parse(userRaw) : null; // الحذف localStorage.removeItem("theme"); localStorage.clear(); // حذف الكل // ─── Wrapper احترافي مع معالجة الأخطاء ─── const Store = { set(key, value) { try { localStorage.setItem(key, JSON.stringify(value)); return true; } catch { return false; } // لو الذاكرة ممتلئة }, get(key, fallback = null) { try { return JSON.parse(localStorage.getItem(key)) ?? fallback; } catch { return fallback; } }, del(key) { localStorage.removeItem(key); }, has(key) { return localStorage.getItem(key) !== null; } }; // الاستخدام Store.set("player", { name:"Ahmed", score:999 }); const p = Store.get("player", { name:"Guest", score:0 });
⚠️ LocalStorage متزامن (Synchronous) ويمكن أن يُبطئ الموقع مع البيانات الكبيرة. للبيانات الكبيرة استخدم IndexedDB.
// IndexedDB — قاعدة بيانات كاملة في المتصفح (GBs) // نستخدم مكتبة idb لتبسيطها // <script src="https://cdn.jsdelivr.net/npm/idb@7/build/umd.js"></script> const { openDB } = idb; // ─── فتح / إنشاء قاعدة البيانات ─── const dbPromise = openDB("PhineXGameDB", 1, { upgrade(db) { // إنشاء Object Store (مثل الجدول) const store = db.createObjectStore("players", { keyPath: "id", autoIncrement: true }); store.createIndex("score", "score"); // فهرس للبحث السريع store.createIndex("rank", "rank"); } }); // ─── CRUD ─── const GameDB = { async addPlayer(data) { const db = await dbPromise; return db.add("players", data); }, async getAll() { const db = await dbPromise; return db.getAll("players"); }, async updateScore(id, score) { const db = await dbPromise; const player = await db.get("players", id); return db.put("players", { ...player, score }); } };
🔗

REST API Patterns

كيف تتحدث مع أي سيرفر بشكل احترافي — GET, POST, PUT, DELETE

// ─── API Client احترافي قابل لإعادة الاستخدام ─── class ApiClient { constructor(baseURL, token = null) { this.baseURL = baseURL; this.token = token; } _headers() { const h = { "Content-Type": "application/json" }; if (this.token) h["Authorization"] = `Bearer ${this.token}`; return h; } async _request(method, path, body = null) { const opts = { method, headers: this._headers() }; if (body) opts.body = JSON.stringify(body); const res = await fetch(this.baseURL + path, opts); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.message || `HTTP ${res.status}`); } return res.status !== 204 ? res.json() : null; } get(path) { return this._request("GET", path); } post(path, body) { return this._request("POST", path, body); } put(path, body) { return this._request("PUT", path, body); } patch(path, body) { return this._request("PATCH", path, body); } delete(path) { return this._request("DELETE", path); } } // ─── الاستخدام ─── const api = new ApiClient("https://api.mygame.com", userToken); const players = await api.get("/players?limit=10"); const newPlayer = await api.post("/players", { name:"Ahmed" }); await api.patch(`/players/${id}/score`, { points: 50 }); await api.delete(`/players/${id}`);

📊 متى تختار أي نظام؟

المعيار Firebase Supabase MongoDB LocalStorage
نوع البيانات NoSQL مرن SQL منظم NoSQL مستندات نص/JSON فقط
Real-time ممتاز ممتاز يحتاج إعداد لا
سهولة البداية سهل جداً متوسط يحتاج Backend سهل جداً
الاستعلامات محدودة SQL كامل قوية جداً يدوية
التخزين سحابي سحابي سحابي/محلي المتصفح فقط
مثالي لـ تطبيقات تسجيل دخول، ألعاب، دردشة SaaS، متاجر، منصات اجتماعية APIs كبيرة، بيانات معقدة إعدادات، ذاكرة تخزين مؤقت

🏆 جاهز للاختبار؟

اختبر معرفتك بكل مواضيع الكورس — 30 سؤالاً

الاختبار النهائي ⚡ المراجعة الشاملة 📖