# Multi-Tenant System Documentation

This document explains the multi-tenant architecture implemented in the application, focusing on how tenants are identified, validated, and isolated.

## Overview

The application implements a multi-tenant architecture where each tenant (school/creche) has its own isolated data context. The system uses a combination of middleware, guards, and database context isolation to ensure proper tenant separation.

## Tenant Identification

Tenants are identified through two primary methods:

1. **HTTP Header**: `x-tenant-slug` header
2. **Subdomain**: The first part of the hostname (e.g., `tenant1.example.com`)

The system prioritizes the header method over subdomain detection.

## Middleware

### TenantMiddleware

Located at `apps/api/src/shared/middleware/tenant.middleware.ts`, this middleware:

- Runs on all requests (except public routes)
- Extracts tenant information from requests
- Validates tenant existence and active status
- Sets tenant context for database operations
- Uses `AsyncLocalStorage` to maintain tenant context across async operations

### LoggerMiddleware

Located at `apps/api/src/shared/middleware/logger.middleware.ts`, this middleware:

- Logs all HTTP requests
- Includes tenant information in logs when available
- Runs on all requests

## Guards

### TenantGuard

Located at `apps/api/src/shared/guards/tenant.guard.ts`, this guard:

- Ensures tenant context is properly set for authenticated requests
- Verifies tenant ownership of resources
- Used in routes that require tenant context

### JwtAuthGuard

Located at `apps/api/src/shared/guards/jwt-auth.guard.ts`, this guard:

- Validates JWT tokens for authentication
- Ensures requests are properly authenticated
- Used as a base for other authentication guards

### RolesGuard

Located at `apps/api/src/shared/guards/roles.guard.ts`, this guard:

- Validates user roles for access control
- Used in routes that require specific user roles

### PlatformAdminGuard

Located at `apps/api/src/shared/guards/platform-admin.guard.ts`, this guard:

- Validates platform admin access
- Used for routes that require super admin privileges

## Public Routes

Routes that don't require tenant validation are defined in `apps/api/src/shared/constants/public-routes.ts`:

- Authentication endpoints (`/api/v1/auth/*`)
- Tenant registration and verification (`/api/v1/tenants/*`)
- Health checks (`/api/v1/health`, `/api/health`)
- Documentation (`/api/docs`)
- Platform admin endpoints (`/api/v1/platform/*`)
- Super admin endpoints (`/api/v1/admin/*`)

## Database Context Isolation

The system uses Prisma's `AsyncLocalStorage` context to isolate database operations by tenant. This ensures that:

- All database queries automatically include the tenant filter
- Data from different tenants cannot be accidentally accessed
- The `tenantContext` in `apps/api/src/shared/prisma/tenant-context.ts` manages the tenant context

## Implementation Details

### Tenant Context

The tenant context is managed through `AsyncLocalStorage` in `apps/api/src/shared/prisma/tenant-context.ts`. This allows for proper context propagation in asynchronous operations.

### Tenant Validation Flow

1. Middleware checks if route is public (bypasses tenant validation)
2. Extracts tenant slug from header or subdomain
3. Validates tenant exists and is active
4. Sets tenant context for database operations
5. Proceeds with request handling

## Security Considerations

1. **Tenant Isolation**: All database operations are automatically scoped to the current tenant
2. **Authentication**: All routes require proper authentication
3. **Authorization**: Roles guard ensures users have appropriate permissions
4. **Public Routes**: Carefully maintained to prevent unauthorized access to tenant data

## Usage Examples

### Setting Tenant Header

```
curl -H "x-tenant-slug: my-tenant-slug" http://localhost:3001/api/v1/some-endpoint
```

### Subdomain Access

```
http://my-tenant-slug.example.com:3001/api/v1/some-endpoint
```

## Adding New Public Routes

To add a new public route, simply add the route prefix to `apps/api/src/shared/constants/public-routes.ts`:

```typescript
export const PUBLIC_ROUTE_PREFIXES: readonly string[] = [
  // ... existing routes
  '/api/v1/new-public-endpoint', // Add new route here
];
```

This ensures the new endpoint bypasses tenant validation while maintaining security for all other routes.