# Territory Filtering System This document describes the territory filtering system implemented for Black Canyon Tickets, which provides role-based access control at the territory level. ## Overview The territory filtering system ensures that users can only see and manage data within their assigned territories, while providing administrators with flexible filtering capabilities. ## Components ### Core Components 1. **TerritoryFilter.tsx** - UI component for territory selection and display 2. **useTerritoryFilter.ts** - Hook for managing territory filter state with URL persistence 3. **useClaims.ts** - Hook for accessing user role and territory assignments 4. **Query hooks** - Territory-aware data fetching hooks ### Data Layer 1. **queries/events.ts** - Events filtering with territory restrictions 2. **queries/ticketTypes.ts** - Ticket types filtering with territory validation 3. **queries/tickets.ts** - Tickets filtering with territory-based access ## Role-based Access Control ### Territory Manager - **Access**: Limited to assigned territories only - **Filter Control**: Cannot modify territory selection (read-only) - **Data Visibility**: Only events, tickets, and ticket types in assigned territories - **UI Behavior**: Shows badge indicating territory restriction ### Organization Admin / Super Admin - **Access**: Can view all territories in organization - **Filter Control**: Full control over territory selection - **Data Visibility**: All data by default, can filter by selected territories - **UI Behavior**: Shows selectable multi-territory filter with URL persistence ### Staff - **Access**: Full access within organization (can be restricted in future) - **Filter Control**: Full control over territory selection - **Data Visibility**: All organization data, respects territory filters ## Implementation Details ### URL Persistence - Territory filters persist in URL parameters (`?territories=AAA,BBB`) - LocalStorage fallback for admin users - Territory managers don't affect URL (their territories are fixed) ### Query Batching The `applyTerritoryFilter` utility handles Firestore's 10-item limit for `in` queries by automatically batching larger territory lists: ```typescript // Handles >10 territories by creating multiple query batches const chunks = []; for (let i = 0; i < territoryIds.length; i += 10) { chunks.push(territoryIds.slice(i, i + 10)); } ``` ### Filter States - **isActive**: Territory filter is currently applied - **isFiltered**: Data is being filtered (either by role or by admin selection) - **canModifySelection**: User can change territory selection ## Usage Examples ### EventsIndexPage ```tsx import { TerritoryFilter } from '../../features/territory/TerritoryFilter'; import { useTerritoryFilter } from '../../features/territory/useTerritoryFilter'; import { useEventsQuery } from '../../queries/events'; function EventsIndexPage() { const { selectedTerritoryIds, setSelectedTerritories, canModifySelection } = useTerritoryFilter(); const { events, isFiltered } = useEventsQuery(selectedTerritoryIds); return (
{/* Event list filtered by territories */}
); } ``` ### EventDetailPage ```tsx function EventDetailPage() { const { selectedTerritoryIds, isActive, clearAll } = useTerritoryFilter(); return (
{/* Active filter banner */} {isActive && (
Filtered by: {territoryNames}
)}
); } ``` ## Testing ### Unit Tests - `TerritoryFilter.test.tsx` - Component behavior for different roles - `territory-filtering.test.ts` - Query filtering logic and access control ### Test Coverage - ✅ Territory manager sees only assigned events - ✅ Admin can filter via territory selection - ✅ URL state persistence works correctly - ✅ Query batching handles >10 territories - ✅ Role-based access matrix validation - ✅ Error handling for missing claims ## Security Considerations 1. **Server-side Validation**: All territory restrictions must be enforced on the backend 2. **Row Level Security**: Database queries should include territory filtering at the RLS level 3. **Claims Validation**: Territory assignments are stored in Firebase custom claims 4. **Data Isolation**: Each territory's data is completely isolated from others ## Performance Optimization 1. **Query Batching**: Automatic handling of Firestore's 10-item `in` limit 2. **Memoization**: Territory filtering logic is memoized to prevent unnecessary re-renders 3. **Lazy Loading**: Territory data is loaded on-demand 4. **URL Persistence**: Reduces unnecessary API calls by preserving filter state ## Future Enhancements 1. **Hierarchical Territories**: Support for territory hierarchies and inheritance 2. **Territory Permissions**: Fine-grained permissions within territories 3. **Multi-organization Support**: Territory filtering across multiple organizations 4. **Analytics Integration**: Territory-based analytics and reporting ## Migration Notes When implementing this system: 1. Update all existing queries to use territory-aware hooks 2. Add territory banners to relevant pages 3. Test role-based access thoroughly 4. Ensure URL state persistence works correctly 5. Validate query performance with large territory lists