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

9.3 KiB

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

// 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

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:

// 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:

// 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:

// 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:

// Only visible to superadmin and orgAdmin
// Updates Firebase custom claims
// Provides visual feedback for claim changes
<UserTerritoryManager />

Event Creation

Territory selection is mandatory:

// EventDetailsStep includes territory dropdown
// Auto-selects for territory managers with single territory
// Validates territory access before save

Hooks

useClaims

Access Firebase custom claims:

const { claims, loading, error, refreshClaims } = useClaims();
// claims.orgId, claims.role, claims.territoryIds

useTerritoryEvents

Territory-filtered event access:

const { 
  events,           // Filtered by territory access
  canAccessEvent,   // Check event permissions
  canModifyEvent,   // Check edit permissions
  createEvent       // Validates territory on create
} = useTerritoryEvents();

useTerritoryFilter

Filter state management:

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

// 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:

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

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)

GET /api/admin/users/:uid/claims
Authorization: Bearer <firebase-id-token>

Frontend API

Territory Filtering

// 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

// 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

// 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