تضغط «حفظ» أو «إرسال» في منتجك وما يصير شي، وفي تبويب Console تلقى: new row violates row-level security policy for table "orders". أو ترفع صورة وتطلع نفس الرسالة على جدول objects. هذا خطأ من Supabase، ونشوفه كثير في المنتجات المبنية بـ Lovable و Bolt. معناه باختصار: قاعدة البيانات رفضت تحفظ السطر لأن ما فيه قاعدة تسمح لهذا المستخدم يضيفه.
الخبر الزين: هذا الخطأ علامة إن الحماية شغّالة. الخبر الثاني: أسهل «حل» له هو أخطر حل.
إيش يعني بالضبط
في Supabase، المتصفح يكلّم قاعدة البيانات مباشرة. عشان كذا فيه شي اسمه Row Level Security، أو RLS: قواعد على كل جدول تقول مين يقدر يقرأ، ومين يضيف، ومين يعدّل، ومين يحذف، وأي سطور بالضبط. لما يكون RLS مفعّل على جدول وما فيه قاعدة تسمح بالإضافة، أو فيه قاعدة لكن السطر الجديد ما يطابق شرطها، قاعدة البيانات ترفض وترجع هذا الخطأ.
ليش يطلع كثير في المنتجات المبنية بالذكاء الاصطناعي
- قاعدة للقراءة فقط: الأداة كتبت قاعدة SELECT عشان الصفحة تعرض البيانات، ونسيت قاعدة INSERT.
- عمود صاحب السطر فاضي: القاعدة تقول «المستخدم يضيف سطر إذا
user_idيساوي رقمه»، والكود ما يرسلuser_idأصلًا، أو يرسل رقم ثاني. - المستخدم مو مسجّل دخول: الطلب يوصل كزائر (
anon)، والقاعدة مكتوبة للمسجّلين (authenticated). - الإضافة ثم القراءة: الكود يضيف السطر ويطلب يرجع له مباشرة (
.insert().select())، فيحتاج قاعدة قراءة بعد قاعدة الإضافة. - upsert: الإضافة أو التعديل في خطوة وحدة تحتاج ثلاث قواعد: إضافة، وتعديل، وقراءة، لأن قاعدة البيانات تقرأ السطر الموجود قبل ما تعدّله.
- رفع الملفات: التخزين في Supabase نفسه جدول عليه RLS. رفع صورة لـ bucket بدون قاعدة على
storage.objectsيطلع نفس الخطأ.
كيف تتأكد بنفسك
- افتح منتجك، واضغط F12، وافتح تبويب Network، وسوّ الحركة اللي تفشل.
- دوّر على الطلب الأحمر. رابطه غالبًا فيه
/rest/v1/واسم الجدول، أو/storage/v1/للملفات. في/rest/v1/الرد يكون 401 إذا الطلب من زائر، و 403 إذا من مستخدم مسجّل. وفي/storage/v1/الرد غالبًا 400، وداخله"statusCode": "403"ونص الخطأ. - في لوحة Supabase، افتح صفحة Policies، ودوّر على الجدول نفسه. شوف: فيه قاعدة لـ INSERT؟ لمين هي،
anonولاauthenticated؟ وإيش الشرط اللي فيها؟ - ارجع للطلب في تبويب Network وشوف إيش أرسل الكود. إذا القاعدة تشترط
user_idوالطلب ما فيه هالعمود، لقيت السبب.
الحل اللي لا تسويه
لما تطلب من أداة الذكاء الاصطناعي تصلّحه، كثير مرات تقترح واحد من ثلاثة حلول، وكلها تفتح بياناتك:
- تعطيل RLS على الجدول. الخطأ يختفي، لأن الجدول صار مفتوح لأي أحد عنده رابط مشروعك والمفتاح العام، وهذا المفتاح موجود في كود الواجهة يشوفه كل زائر. يعني أي أحد يقدر يقرأ ويعدّل ويحذف كل السطور.
- قاعدة شرطها `true`. نفس النتيجة بشكل ثاني: RLS «مفعّل» على الورق، والقاعدة تسمح لكل الناس بكل شي.
- استخدام مفتاح `service_role` في الواجهة. هذا المفتاح يتجاوز RLS كله، ومكانه السيرفر فقط. إذا وصل للمتصفح، أي زائر ياخذه ويتحكم في قاعدة بياناتك كاملة. شوف مفتاحك انكشف؟.
الحل الصح
القاعدة الصح تقول بالضبط مين يضيف وإيش يضيف. في أغلب الجداول اللي كل سطر فيها يخص مستخدم:
- قاعدة INSERT للمسجّلين فقط، شرطها إن
user_idفي السطر الجديد يساويauth.uid()، يعني رقم المستخدم اللي سجّل دخول. - الأفضل إن عمود
user_idتكون قيمته الافتراضيةauth.uid()في قاعدة البيانات نفسها، عشان ما يعتمد على الكود يرسلها صح. - قاعدة SELECT بنفس الشرط، عشان المستخدم يشوف سطوره هو فقط، ويقدر الكود يرجع السطر بعد إضافته.
- لو الكود يعدّل، قاعدة UPDATE بنفس الشرط، مع شرط يمنع المستخدم ينقل السطر لحساب ثاني.
بعد ما تكتب القواعد، جرّب بحسابين: سجّل بالأول وأضف شي، وبعدها سجّل بالثاني وتأكد إنه ما يشوفه. هذا الاختبار أهم من اختفاء الخطأ. فحوصات أكثر من هالنوع في 5 ثغرات في تسجيل الدخول.
إذا الجداول كثيرة والقواعد متداخلة
في منتج فيه أدوار، مثل صاحب متجر وموظفين وعملاء، القواعد تصير أعقد، وغلطة وحدة فيها ممكن تكشف بيانات عميل لعميل ثاني بدون أي خطأ يبان. إذا تبي أحد يكتبها ويختبرها معك، مكالمة استشارية تكفي لجدول أو جدولين. إذا عندك جداول كثيرة وما تدري أي منها مفتوح، تدقيق جاهزية الإطلاق يمر عليها كلها. وفيه مشاكل ثانية نشوفها في Lovable و Supabase.