# 🏢 Multi-tenancy Implementation - PraFrota Frontend

## Overview

This document outlines how the PraFrota frontend implements multi-tenancy to align with our backend architecture, ensuring proper tenant isolation and data management.

## 🏗️ Tenant Context

### Tenant Service

```typescript
@Injectable({
  providedIn: 'root'
})
export class TenantService {
  private currentTenant = new BehaviorSubject<Tenant | null>(null);
  
  constructor(private http: HttpClient) {}

  // Get current tenant
  getCurrentTenant(): Observable<Tenant | null> {
    return this.currentTenant.asObservable();
  }

  // Set current tenant
  setCurrentTenant(tenant: Tenant): void {
    this.currentTenant.next(tenant);
  }

  // Load tenant data
  loadTenantData(tenantId: string): Observable<Tenant> {
    return this.http.get<Response<Tenant>>(`/api/tenant/${tenantId}`).pipe(
      map(response => response.data),
      tap(tenant => this.setCurrentTenant(tenant))
    );
  }
}
```

### Tenant Interface

```typescript
interface Tenant {
  id: string;
  name: string;
  settings: TenantSettings;
  features: string[];
  permissions: string[];
}
```

## 🔐 Authentication & Authorization

### Auth Interceptor

```typescript
@Injectable()
export class TenantAuthInterceptor implements HttpInterceptor {
  constructor(private tenantService: TenantService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.tenantService.getCurrentTenant().pipe(
      take(1),
      switchMap(tenant => {
        if (!tenant) {
          return next.handle(req);
        }

        const modifiedReq = req.clone({
          setHeaders: {
            'tenant-uuid': tenant.id,
            'tenant-user-auth': this.getAuthToken()
          }
        });

        return next.handle(modifiedReq);
      })
    );
  }

  private getAuthToken(): string {
    // Get token from secure storage
    return localStorage.getItem('auth_token') || '';
  }
}
```

## 📦 Data Isolation

### Tenant-specific Storage

```typescript
@Injectable({
  providedIn: 'root'
})
export class TenantStorageService {
  private readonly TENANT_PREFIX = 'tenant_';

  constructor(private tenantService: TenantService) {}

  // Store tenant-specific data
  setItem(key: string, value: any): void {
    this.tenantService.getCurrentTenant().pipe(
      take(1)
    ).subscribe(tenant => {
      if (tenant) {
        const tenantKey = `${this.TENANT_PREFIX}${tenant.id}_${key}`;
        localStorage.setItem(tenantKey, JSON.stringify(value));
      }
    });
  }

  // Get tenant-specific data
  getItem<T>(key: string): Observable<T | null> {
    return this.tenantService.getCurrentTenant().pipe(
      take(1),
      map(tenant => {
        if (!tenant) return null;
        const tenantKey = `${this.TENANT_PREFIX}${tenant.id}_${key}`;
        const value = localStorage.getItem(tenantKey);
        return value ? JSON.parse(value) : null;
      })
    );
  }
}
```

## 🔄 Tenant Switching

### Tenant Switch Component

```typescript
@Component({
  selector: 'app-tenant-switch',
  standalone: true,
  template: `
    <div class="tenant-switch">
      <select [formControl]="tenantControl" (change)="onTenantChange()">
        <option *ngFor="let tenant of tenants" [value]="tenant.id">
          {{tenant.name}}
        </option>
      </select>
    </div>
  `
})
export class TenantSwitchComponent {
  tenantControl = new FormControl('');
  tenants: Tenant[] = [];

  constructor(
    private tenantService: TenantService,
    private router: Router
  ) {}

  onTenantChange(): void {
    const tenantId = this.tenantControl.value;
    if (tenantId) {
      this.tenantService.loadTenantData(tenantId).subscribe(() => {
        // Clear tenant-specific data
        this.clearTenantData();
        // Reload current route
        this.router.navigateByUrl(this.router.url);
      });
    }
  }

  private clearTenantData(): void {
    // Clear tenant-specific data from storage
    // Clear tenant-specific state
    // Clear tenant-specific cache
  }
}
```

## 📊 Tenant-specific Features

### Feature Flags

```typescript
@Injectable({
  providedIn: 'root'
})
export class FeatureFlagService {
  constructor(private tenantService: TenantService) {}

  isFeatureEnabled(feature: string): Observable<boolean> {
    return this.tenantService.getCurrentTenant().pipe(
      map(tenant => tenant?.features.includes(feature) ?? false)
    );
  }
}
```

### Feature Guard

```typescript
@Injectable({
  providedIn: 'root'
})
export class FeatureGuard implements CanActivate {
  constructor(
    private featureFlagService: FeatureFlagService,
    private router: Router
  ) {}

  canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
    const requiredFeature = route.data['requiredFeature'];
    return this.featureFlagService.isFeatureEnabled(requiredFeature).pipe(
      tap(enabled => {
        if (!enabled) {
          this.router.navigate(['/unauthorized']);
        }
      })
    );
  }
}
```

## 📝 Best Practices

1. **Data Isolation**:
   - Always use tenant-specific storage
   - Clear tenant data on switch
   - Validate tenant context

2. **Security**:
   - Always include tenant headers
   - Validate tenant permissions
   - Handle unauthorized access

3. **Performance**:
   - Cache tenant-specific data
   - Optimize tenant switching
   - Handle offline scenarios

4. **User Experience**:
   - Show tenant context
   - Handle tenant switching gracefully
   - Provide clear feedback

## 🔄 Implementation Checklist

When implementing tenant-specific features:

1. [ ] Add tenant headers to requests
2. [ ] Implement tenant storage
3. [ ] Add feature flags
4. [ ] Implement tenant switching
5. [ ] Add proper validation
6. [ ] Handle errors appropriately
7. [ ] Test all scenarios

## 📚 Additional Resources

- Backend Multi-tenancy: `/docs/mcp/MULTI_TENANCY.md`
- Frontend Architecture: `/docs/ARCHITECTURE.md`
- Authentication Guide: `/docs/AUTHENTICATION.md` 