Configure Firestore security rules to protect StockPro data
Firebase Security Rules control access to your Firestore database and Firebase Storage. This guide provides comprehensive security rules for StockPro’s collections and best practices for securing your inventory system.
Critical: Deploy security rules before going to production!Without proper security rules, anyone can read, modify, or delete your entire database. This is a critical security vulnerability that must be addressed.
Here’s a complete, production-ready security rules configuration for StockPro:
firestore.rules
rules_version = '2';service cloud.firestore { match /databases/{database}/documents { // Helper function: Check if user is authenticated function isAuthenticated() { return request.auth != null; } // Helper function: Get user document function getUserData() { return get(/databases/$(database)/documents/usuarios/$(request.auth.uid)).data; } // Helper function: Check if user is admin function isAdmin() { return isAuthenticated() && getUserData().tipo == 'admin'; } // Helper function: Check if user is admin or manager function isAdminOrManager() { return isAuthenticated() && (getUserData().tipo == 'admin' || getUserData().tipo == 'gerente'); } // Helper function: Check if user owns the document function isOwner(userId) { return isAuthenticated() && request.auth.uid == userId; } // Usuario Collection Rules match /usuarios/{userId} { // Users can read their own profile allow get: if isAuthenticated() && (request.auth.uid == userId || isAdminOrManager()); // Admin and managers can list all users allow list: if isAdminOrManager(); // Only admins can create new users allow create: if isAdmin() && request.resource.data.keys().hasAll(['uid', 'name', 'email', 'tipo']) && request.resource.data.uid is string && request.resource.data.name is string && request.resource.data.email is string && request.resource.data.tipo in ['admin', 'gerente', 'empleado']; // Users can update their own profile (except tipo field) // Admins can update any profile allow update: if isAuthenticated() && ( (request.auth.uid == userId && !request.resource.data.diff(resource.data).affectedKeys().hasAny(['tipo', 'uid'])) || isAdmin() ); // Only admins can delete users allow delete: if isAdmin(); } // Productos Collection Rules match /productos/{productId} { // All authenticated users can read products allow get, list: if isAuthenticated(); // Admin and managers can create products allow create: if isAdminOrManager() && request.resource.data.keys().hasAll(['nombre', 'precio', 'cantidad', 'categoria']) && request.resource.data.nombre is string && request.resource.data.precio is number && request.resource.data.precio > 0 && request.resource.data.cantidad is number && request.resource.data.cantidad >= 0 && request.resource.data.categoria is string; // Admin and managers can update products allow update: if isAdminOrManager() && request.resource.data.precio > 0 && request.resource.data.cantidad >= 0; // Only admins can delete products allow delete: if isAdmin(); } // Ventas Collection Rules match /ventas/{ventaId} { // All authenticated users can read sales allow get, list: if isAuthenticated(); // All authenticated users can create sales allow create: if isAuthenticated() && request.resource.data.keys().hasAll(['productos', 'total', 'fecha', 'usuario']) && request.resource.data.productos is list && request.resource.data.total is number && request.resource.data.total > 0 && request.resource.data.fecha is timestamp && request.resource.data.usuario == request.auth.uid; // Sales cannot be updated (immutable for audit trail) allow update: if false; // Only admins can delete sales (for corrections) allow delete: if isAdmin(); } // Reportes Collection Rules match /reportes/{reporteId} { // Admin and managers can read reports allow get, list: if isAdminOrManager(); // System-generated reports (usually via Cloud Functions) // Admin and managers can create manual reports allow create: if isAdminOrManager(); // Reports cannot be updated (immutable for audit trail) allow update: if false; // Only admins can delete reports allow delete: if isAdmin(); } // Deny all other collections by default match /{document=**} { allow read, write: if false; } }}
// Bad: Too permissiveallow read, write: if isAuthenticated();// Good: Specific permissionsallow get: if isOwner(userId);allow update: if isOwner(userId) && validUpdate();allow delete: if isAdmin();
match /ventas/{ventaId} { allow create: if isAuthenticated(); allow update: if false; // Sales cannot be modified allow delete: if isAdmin(); // Only admins can delete for corrections}
match /pedidos/{pedidoId} { allow read: if request.auth.uid == resource.data.userId; allow create: if request.auth.uid == request.resource.data.userId;}