Firestore rules are not boilerplate you paste once. They are the contract between your app and your database. On OzSathi and Dhukuti I learned to write three patterns first, then build features on top.
1. Signed-in gate
Most collections should not be world-readable. A simple helper keeps rules readable:
function isSignedIn() { return request.auth != null; }
Public reads exist only where marketing needs them. Everything user-generated starts
behind isSignedIn().
2. Owner match
Users edit their own docs. Admins override. The pattern:
resource.data.userId == request.auth.uidon update and delete- Same check on create via
request.resource.data.userId - Admin role stored in custom claims or a small
adminscollection
OzSathi listings use this for drafts. Dhukuti circle members can only update their own profile fields inside a circle.
3. Field-level discipline
Clients lie. Rules should allow only the fields you expect to change. If status moves
from pending to verified, that transition belongs in a Cloud
Function or admin tool, not an open client write.
What I test before deploy
- Anonymous user cannot read private collections
- User A cannot edit user B's document
- Valid owner can create, read, update within allowed fields
- Admin paths still work for moderation
The Firebase emulator and rules unit tests save hours. I run them before every rules deploy now. Boring? Yes. Cheaper than a data leak on a community app.
Building with Firebase too? Get in touch or read how OzSathi and Dhukuti use the same stack end to end.