Firestore Security Rules
Below is a baseline ruleset aligned with the app’s access patterns. Adjust as needed for your organization.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
function isParticipant(businessId) {
return isSignedIn() && exists(/databases/$(database)/documents/businesses/$(businessId)/participants/$(request.auth.uid));
}
match /users/{userId} {
allow read: if isSignedIn() && request.auth.uid == userId;
allow create, update: if isSignedIn() && request.auth.uid == userId;
allow delete: if false;
}
match /businesses/{businessId} {
allow read: if isParticipant(businessId);
allow create, update, delete: if false;
match /participants/{participantId} {
allow read: if isParticipant(businessId) && request.auth.uid == participantId;
allow create: if isSignedIn() && request.auth.uid == participantId;
allow update: if isSignedIn() && request.auth.uid == participantId
&& (!('uid' in request.resource.data) || request.resource.data.uid == participantId)
&& request.resource.data.isOnboarded == resource.data.isOnboarded;
allow delete: if false;
}
match /posts/{postId} {
// Read-only from clients; server functions handle writes
allow read: if isParticipant(businessId);
allow create, update, delete: if false;
}
match /companyLinkedInPosts/{docId} {
// Read-only from clients; ingestion via server functions
allow read: if isParticipant(businessId);
allow create, update, delete: if false;
}
}
}
}
Notes:
- Participants can read their own participant document and the parent business doc; they cannot modify
isOnboardedor other sensitive fields directly. - Client-side writes to
postsandcompanyLinkedInPostsare disabled; ingestion happens through HTTPS Functions that enforcex-api-key. - If you introduce admin roles, expand
isParticipantor add anisAdminhelper to permit privileged access patterns.
Deploy:
- Save rules in the repo root as
firestore.rulesand deploy viafirebase deploy --only firestore:rules.