- Add comprehensive analytics components with export functionality - Implement territory management with manager performance tracking - Add seatmap components for venue layout management - Create customer management features with modal interface - Add advanced hooks for dashboard flags and territory data - Implement seat selection and venue management utilities - Add type definitions for ticketing and seatmap systems 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
94 lines
3.8 KiB
Plaintext
94 lines
3.8 KiB
Plaintext
rules_version = '2';
|
|
|
|
service cloud.firestore {
|
|
match /databases/{database}/documents {
|
|
// Helper functions
|
|
function inOrg(orgId) {
|
|
return request.auth != null && request.auth.token.orgId == orgId;
|
|
}
|
|
|
|
function canWriteOrg(orgId) {
|
|
return inOrg(orgId) && (request.auth.token.role in ['superadmin', 'orgAdmin']);
|
|
}
|
|
|
|
function territoryOK(resOrgId, resTerritoryId) {
|
|
return inOrg(resOrgId) && (
|
|
request.auth.token.role in ['superadmin', 'orgAdmin'] ||
|
|
(request.auth.token.role == 'territoryManager' && (resTerritoryId in request.auth.token.territoryIds)) ||
|
|
request.auth.token.role == 'staff' // staff sees entire org; can narrow later
|
|
);
|
|
}
|
|
|
|
function canReadTerritory(resOrgId, resTerritoryId) {
|
|
return inOrg(resOrgId) && (
|
|
request.auth.token.role in ['superadmin', 'orgAdmin'] ||
|
|
(request.auth.token.role == 'territoryManager' && (resTerritoryId in request.auth.token.territoryIds)) ||
|
|
request.auth.token.role == 'staff'
|
|
);
|
|
}
|
|
|
|
// Organizations collection
|
|
match /orgs/{orgId} {
|
|
allow read, write: if inOrg(orgId);
|
|
allow create: if request.auth != null;
|
|
}
|
|
|
|
// Users collection for organization membership tracking
|
|
match /users/{userId} {
|
|
// Users can read their own document, or admins can read within their org
|
|
allow read: if (request.auth != null && request.auth.uid == userId) ||
|
|
(request.auth != null && inOrg(resource.data.orgId));
|
|
|
|
// Only orgAdmins and superadmins can write user documents
|
|
allow write: if request.auth != null &&
|
|
canWriteOrg(request.resource.data.orgId);
|
|
}
|
|
|
|
// Territories collection
|
|
match /territories/{territoryId} {
|
|
allow read: if inOrg(resource.data.orgId);
|
|
allow write: if canWriteOrg(request.resource.data.orgId);
|
|
}
|
|
|
|
// Events collection with territory scoping
|
|
match /events/{eventId} {
|
|
allow read: if canReadTerritory(resource.data.orgId, resource.data.territoryId);
|
|
allow write: if territoryOK(request.resource.data.orgId, request.resource.data.territoryId);
|
|
}
|
|
|
|
// Ticket types collection with territory inheritance
|
|
match /ticket_types/{ticketTypeId} {
|
|
allow read: if inOrg(resource.data.orgId);
|
|
allow write: if territoryOK(request.resource.data.orgId, request.resource.data.territoryId);
|
|
}
|
|
|
|
// Tickets collection with territory inheritance
|
|
match /tickets/{ticketId} {
|
|
// Scanning/reporting needs org-wide reads; can narrow if required
|
|
allow read: if inOrg(resource.data.orgId);
|
|
allow write: if territoryOK(request.resource.data.orgId, request.resource.data.territoryId);
|
|
}
|
|
|
|
// Scans collection - append-only audit trail for ticket scanning
|
|
match /scans/{scanId} {
|
|
// Staff and above can read scans within their org for reporting/analytics
|
|
allow read: if inOrg(resource.data.orgId) &&
|
|
request.auth.token.role in ['staff', 'territoryManager', 'orgAdmin', 'superadmin'];
|
|
|
|
// Only create operations allowed - append-only pattern
|
|
// Staff and above can create scan records within their org
|
|
allow create: if inOrg(request.resource.data.orgId) &&
|
|
request.auth.token.role in ['staff', 'territoryManager', 'orgAdmin', 'superadmin'];
|
|
|
|
// Explicitly deny updates and deletes to enforce append-only pattern
|
|
allow update, delete: if false;
|
|
}
|
|
|
|
// Legacy support for old organization membership model
|
|
function isOrgMember(orgId) {
|
|
return request.auth != null &&
|
|
exists(/databases/$(database)/documents/users/$(request.auth.uid)) &&
|
|
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.orgs[orgId] != null;
|
|
}
|
|
}
|
|
} |