rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // Helper: check if the authenticated user is an admin function isAdmin() { return request.auth != null && request.auth.token.email in get(/databases/$(database)/documents/config/admins).data.emails; } // Config collection (admin allowlist etc.) match /config/{docId} { allow read: if request.auth != null; // Allow initial creation (bootstrap) by authenticated user; updates only by admins allow create: if request.auth != null; allow update: if isAdmin(); allow delete: if false; } // Students collection (read-only, managed via admin/console) match /students/{studentId} { allow read: if true; allow write: if false; } // Donors collection match /donors/{donorId} { // Anyone can read donors allow read: if true; // Authenticated users can create donors; admins can also update/delete allow create: if request.auth != null; allow update, delete: if isAdmin(); } // Comments collection match /comments/{commentId} { // Anyone can read comments allow read: if true; // Only authenticated users can create comments allow create: if request.auth != null && request.resource.data.userId == request.auth.uid && request.resource.data.text is string && request.resource.data.text.size() > 0 && request.resource.data.text.size() <= 500; // Users can only delete their own comments allow delete: if request.auth != null && resource.data.userId == request.auth.uid; // No updates to comments allow update: if false; } // Pending donations (created before payment, confirmed via webhook) match /pendingDonations/{donationId} { allow create: if true; allow read, update, delete: if false; } // Newsletter subscribers match /subscribers/{subscriberId} { allow create: if true; allow read, update, delete: if false; } } }