A quick recap if you are joining here. In the first post, I got one Lovable database to act like two, a dev side and a prod side, using separate schemas. This post is about the part that worried me most: making sure the wall keeps strangers out.
The most useful thing the database said to me this week was an error. The most dangerous thing it said was the advice that came with it.
I was testing my dev and prod setup. I wanted to be sure a signed-out visitor could not write anything. So I asked Sullivan to try an insert with no sign-in, straight through the client, and report back the exact error.
Here is the prompt:
Try inserting a plate into dev as a signed-out visitor, directly through the client, and report the exact error.Here it is:
status: 401 Unauthorized
code: 42501
message: permission denied for table plates
hint: Grant the required privileges to the current role with: GRANT INSERT ON dev.plates TO anon;The refusal is the good part. The hint is the trap, like a stranger in a trench coat sliding you a note.
Follow that hint and any stranger on the internet can write to my table. The error message is trying to be helpful. It is trying to make the error go away. It does not know that the error is the feature.
Two locks, not one
This is the part I found worth writing down. A table in this setup has two separate locks.
Grants decide who may touch the table at all. A signed-out visitor has no insert grant, so the database stops them at the door. That is the error above.
Row level security decides what a person who got in may do. My policy says only signed-in users may insert.
My signed-out test only proved the first lock. The signed-in inserts I ran earlier proved the second one works for the people it should let through.
Why keep both? Because grants get changed in a hurry. Someone follows a hint, or a tool does, and a grant appears that should not. If the policy is still there, it still holds. One lock failing should not be the end of the story.
What I took from it
A permission error is a result, not a problem to fix. Read it first, then decide.
A suggested fix is written to silence the error. It is not written to keep you safe.
Test the thing you want refused, and write down which layer refused it.
I left the hint alone, and the error stays.


