Files
blackcanyontickets/reactrebuild0825/README-TERRITORY-MANAGERS.md
dzinesco aa81eb5adb feat: add advanced analytics and territory management system
- 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>
2025-08-26 09:25:10 -06:00

345 lines
9.3 KiB
Markdown

# Territory Managers
This document explains the Territory Manager system implemented in Black Canyon Tickets React Rebuild. This system provides role-based access control that restricts users to specific geographic or organizational territories.
## Overview
The Territory Manager system introduces a new user role with limited access permissions based on assigned territories. This enables organizations to segment their operations geographically or by business unit while maintaining centralized management.
## User Roles
### Role Hierarchy
1. **Super Admin** - Platform-wide access across all organizations
2. **Org Admin** - Full access within their organization, can assign territories
3. **Territory Manager** - Limited to assigned territories within their organization
4. **Staff** - Organization-wide read access (can be narrowed in future)
### Territory Manager Capabilities
- View and manage events only in assigned territories
- Create new events (must assign to accessible territory)
- View tickets and customers for accessible events
- Cannot modify events outside their territories
- Cannot assign territories to other users
## Architecture
### Data Model
#### Firestore Collections
```typescript
// territories/{territoryId}
interface Territory {
id: string;
orgId: string;
name: string; // "West Northwest"
code: string; // "WNW"
description?: string;
}
// events/{eventId}
interface Event {
// ... existing fields
organizationId: string;
territoryId: string; // Required field
}
// ticket_types/{ticketTypeId}
interface TicketType {
// ... existing fields
territoryId: string; // Inherited from event
}
// tickets/{ticketId}
interface Ticket {
// ... existing fields
territoryId: string; // Inherited from event
}
// users/{uid} - Mirror of custom claims for UI
interface User {
orgId: string;
role: 'superadmin' | 'orgAdmin' | 'territoryManager' | 'staff';
territoryIds: string[];
}
```
#### Firebase Custom Claims
```typescript
interface CustomClaims {
orgId: string;
role: 'superadmin' | 'orgAdmin' | 'territoryManager' | 'staff';
territoryIds: string[]; // Empty array for full access roles
}
```
### Security Implementation
#### Firestore Security Rules
Access is controlled at the database level using custom claims:
```javascript
// Events collection
allow read: if canReadTerritory(resource.data.orgId, resource.data.territoryId);
allow write: if territoryOK(request.resource.data.orgId, request.resource.data.territoryId);
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))
);
}
```
#### API Authorization
Cloud Functions validate claims before processing requests:
```typescript
// functions/src/claims.ts
function canManageClaims(user: AuthorizedUser, targetOrgId: string): boolean {
if (user.role === 'superadmin') return true;
if (user.role === 'orgAdmin' && user.orgId === targetOrgId) return true;
return false;
}
```
## Frontend Implementation
### Components
#### TerritoryFilter
Role-based filtering component:
```typescript
// Territory managers: fixed to assigned territories
// Admins: multi-select all org territories
// Persists selection in URL params and localStorage
<TerritoryFilter
selectedTerritoryIds={selectedIds}
onSelectionChange={setSelectedIds}
/>
```
#### UserTerritoryManager
Admin interface for assigning territories:
```typescript
// Only visible to superadmin and orgAdmin
// Updates Firebase custom claims
// Provides visual feedback for claim changes
<UserTerritoryManager />
```
#### Event Creation
Territory selection is mandatory:
```typescript
// EventDetailsStep includes territory dropdown
// Auto-selects for territory managers with single territory
// Validates territory access before save
```
### Hooks
#### useClaims
Access Firebase custom claims:
```typescript
const { claims, loading, error, refreshClaims } = useClaims();
// claims.orgId, claims.role, claims.territoryIds
```
#### useTerritoryEvents
Territory-filtered event access:
```typescript
const {
events, // Filtered by territory access
canAccessEvent, // Check event permissions
canModifyEvent, // Check edit permissions
createEvent // Validates territory on create
} = useTerritoryEvents();
```
#### useTerritoryFilter
Filter state management:
```typescript
const {
selectedTerritoryIds,
isActive,
canModifySelection, // False for territory managers
setSelectedTerritories
} = useTerritoryFilter();
```
## Usage Guide
### For Administrators
#### Assigning Territories
1. Navigate to Admin panel
2. Use **UserTerritoryManager** component
3. Select user and role
4. Choose territories (required for territory managers)
5. Save - user must re-login to see changes
#### Creating Territories
```typescript
// Add to MOCK_TERRITORIES for development
// In production, create via admin interface
const territory = {
id: 'territory_004',
orgId: 'org_001',
name: 'Southwest Region',
code: 'SW',
description: 'Arizona, Nevada operations'
};
```
### For Territory Managers
#### Event Management
- Events list automatically filtered to assigned territories
- Create events by selecting accessible territory
- Edit/delete only events in assigned territories
- Territory filter is read-only
#### Dashboard Views
- Revenue and analytics scoped to accessible territories
- Customer data limited to accessible events
- Reporting reflects territorial scope
### For Developers
#### Testing Territory Access
Run comprehensive test suite:
```bash
npm run test:territory # Territory-specific tests
npx playwright test tests/territory-access.spec.ts
```
#### Adding New Territory-Scoped Features
1. Update data models to include `territoryId`
2. Apply filtering in query hooks
3. Add territory validation to mutations
4. Update Firestore security rules
5. Add tests for access control
## API Reference
### Cloud Functions
#### Update User Claims
```http
POST /api/admin/users/:uid/claims
Authorization: Bearer <firebase-id-token>
Content-Type: application/json
{
"orgId": "org_001",
"role": "territoryManager",
"territoryIds": ["territory_001", "territory_002"]
}
```
#### Get User Claims (Debug)
```http
GET /api/admin/users/:uid/claims
Authorization: Bearer <firebase-id-token>
```
### Frontend API
#### Territory Filtering
```typescript
// Apply territory filter to queries
const events = useTerritoryEvents();
const filteredEvents = events.getFilteredEvents();
// Check specific access
const canAccess = events.canAccessEvent(event);
const canModify = events.canModifyEvent(event);
```
#### Claims Management
```typescript
// Access current user claims
const { claims } = useClaims();
if (claims?.role === 'territoryManager') {
// Territory manager specific logic
}
// Refresh claims after admin changes
await refreshClaims();
```
## Security Considerations
### Custom Claims Best Practices
- Claims are authoritative - UI mirrors but never overrides
- Claims update immediately in security rules
- UI requires re-login to reflect claim changes
- Validate claims in all API endpoints
### Access Control Validation
- Database rules enforce access at data layer
- Frontend hooks provide optimistic filtering
- API endpoints validate claims before operations
- Test both UI and database rule enforcement
### Territory Assignment Security
- Only superadmin/orgAdmin can assign territories
- Territory managers cannot escalate privileges
- Cross-organization access strictly prohibited
- Audit trail maintained in users collection
## Troubleshooting
### Common Issues
#### User Claims Not Updating
- Claims update immediately in Firestore security rules
- UI updates require user to re-login
- Check ID token refresh in browser dev tools
- Verify Cloud Function deployment
#### Territory Filter Not Working
- Check URL parameters: `?territories=territory_001,territory_002`
- Verify localStorage: `territory-filter-${orgId}`
- Ensure user has access to selected territories
- Check browser console for access errors
#### Events Not Visible
- Verify event has correct `territoryId`
- Check user's assigned territories in claims
- Confirm organization ID matches
- Test with admin account for comparison
### Debug Commands
```typescript
// Check current claims (browser console)
firebase.auth().currentUser?.getIdTokenResult()
.then(result => console.log(result.claims));
// Verify territory access
const { claims } = useClaims();
const { accessibleTerritoryIds } = useAccessibleTerritories();
console.log({ claims, accessibleTerritoryIds });
```
## Future Enhancements
### Planned Features
- Dynamic territory creation via UI
- Territory-based email notifications
- Advanced reporting with territory breakdowns
- Bulk territory assignment tools
- Territory hierarchy (regions > territories)
### Possible Extensions
- Time-based territory access
- Territory sharing between users
- Territory-specific branding
- Integration with external mapping systems
- Mobile app territory awareness
## Related Documentation
- [Firebase Custom Claims Documentation](https://firebase.google.com/docs/auth/admin/custom-claims)
- [Firestore Security Rules Guide](https://firebase.google.com/docs/firestore/security/get-started)
- [CLAUDE.md](./CLAUDE.md) - Project overview and development guide
- [REBUILD_PLAN.md](./REBUILD_PLAN.md) - Current project status