> ## Documentation Index
> Fetch the complete documentation index at: https://docs.switchbord.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Tenancy e Isolamento de Workspace

> Como a Switchbord impõe isolamento estrito de dados entre organizações tenant, prevenindo o acesso cruzado de dados entre workspaces em todas as camadas.

## Modelo de Isolamento

A Switchbord é uma plataforma multi-tenant onde cada organização tenant opera como um **workspace** independente. A garantia de isolamento é:

> Um usuário no workspace A não pode ler, gravar ou agir sobre dados pertencentes ao workspace B — independentemente de como as chamadas de API são construídas.

Essa garantia é aplicada no lado do servidor, na camada de API, e não apenas por meio de roteamento no cliente ou controles de UI.

## Resolução do Contexto de Workspace

### `resolveCallerWorkspaceFromSupabase(userId)`

Toda rota de API autenticada resolve o contexto de workspace consultando a tabela `workspace_members` usando o ID do usuário autenticado:

```typescript theme={null}
// Somente no servidor — nunca lê variáveis de ambiente ou headers do cliente
async function resolveCallerWorkspaceFromSupabase(userId: string) {
  const { data, error } = await supabase
    .from('workspace_members')
    .select('workspace_id, role')
    .eq('user_id', userId)
    .single();

  if (error || !data) throw new UnauthorizedError();
  return { workspaceId: data.workspace_id, role: data.role };
}
```

Propriedades principais:

* Lê a partir de `workspace_members`, não de variáveis de ambiente
* Retorna o workspace ao qual o usuário realmente pertence — não pode ser sobrescrito por parâmetros de requisição
* Lança erro imediatamente se o usuário não for membro de nenhum workspace
* Usada como base para todo acesso a dados escopado por workspace

### `requireSettingsAccess()`

Todas as 13 rotas de API de configurações usam `requireSettingsAccess()` como sua primeira operação, que chama `resolveCallerWorkspaceFromSupabase` e impõe um nível mínimo de papel antes que qualquer dado de configuração seja lido ou gravado:

```typescript theme={null}
const { workspaceId, role } = await requireSettingsAccess(req, ['owner', 'admin']);
// workspaceId agora é confiável — use-o para todas as consultas subsequentes
```

<Warning>
  Nunca passe `workspaceId` como um parâmetro de query ou campo do corpo da requisição usado para autorização. Sempre derive-o no servidor a partir da sessão autenticada.
</Warning>

## Padrão Descontinuado: `readSingleWorkspace()`

A função `readSingleWorkspace()` lia a configuração de workspace a partir de variáveis de ambiente, o que é incompatível com multi-tenancy. Ela foi **descontinuada e removida** de todos os caminhos de código em produção.

Caminho de migração para qualquer código que ainda a referencie:

```typescript theme={null}
// DESCONTINUADO — não use
const workspace = await readSingleWorkspace();

// CORRETO — resolva a partir do usuário autenticado
const { workspaceId } = await resolveCallerWorkspaceFromSupabase(userId);
const workspace = await getWorkspaceById(workspaceId);
```

## Encadeamento nas Rotas de Configurações

Todas as 13 rotas de API de configurações encadeiam o `workspaceId` derivado de `requireSettingsAccess()` em todas as consultas subsequentes. Nenhuma rota de configurações lê dados de workspace sem primeiro estabelecer o contexto de workspace do chamador.

Exemplo de padrão para uma rota de configurações:

```typescript theme={null}
export async function GET(req: NextRequest) {
  const { workspaceId, role } = await requireSettingsAccess(req, ['owner', 'admin', 'developer']);

  const settings = await db
    .select()
    .from(workspaceSettings)
    .where(eq(workspaceSettings.workspaceId, workspaceId))  // sempre escopado
    .limit(1);

  return Response.json(settings);
}
```

## Isolamento no Despacho de Mensagens

A função `dispatchMessageViaMetaInSupabase` lê as credenciais da Meta a partir do workspace identificado por `job.workspace_id` — o workspace que é proprietário do job, não uma configuração global:

```typescript theme={null}
async function dispatchMessageViaMetaInSupabase(job: MessageJob) {
  // Credenciais buscadas a partir do workspace proprietário deste job
  const credentials = await getWorkspaceMetaCredentials(job.workspace_id);
  // os jobs do workspace A sempre usam o token Meta do workspace A
  return sendViaMetaAPI(credentials, job.payload);
}
```

Isso significa que:

* O workspace A não pode fazer com que mensagens sejam enviadas através do número Meta do Workspace B
* O vazamento de credenciais entre tenants na camada de despacho é estruturalmente impossível
* Cada workspace configura e rotaciona seu próprio token de acesso Meta de forma independente

## Modelo de Entrada Somente por Convite

Os usuários só podem entrar em um workspace por meio de um convite explícito de um admin ou owner de workspace já existente. Não há descoberta ou fluxo de entrada por autoatendimento. Isso garante que:

* A participação no workspace seja sempre intencional
* Novos membros recebam apenas o papel explicitamente concedido pelo admin que convidou
* A remoção de um membro revogue imediatamente todo acesso, incluindo sessões ativas

Veja [Autenticação e Controle de Acesso](/pt-BR/security/authentication) para detalhes sobre revogação de sessão.

## Escopo de Chaves de API

As chaves de API são escopadas ao workspace que as criou. Todas as operações de chave de API (listar, excluir, revogar) filtram pelo `workspace_id` resolvido do chamador:

```typescript theme={null}
// Exclusão de chave de API — sempre escopada ao workspace do chamador
await db.delete(apiKeys)
  .where(
    and(
      eq(apiKeys.id, keyId),
      eq(apiKeys.workspaceId, workspaceId)  // não é possível excluir chaves de outros workspaces
    )
  );
```

## Isolamento do Assistente de IA

O endpoint `/api/ai-assistant` anteriormente não possuía uma guarda de autenticação. Agora ele exige autenticação e resolve o contexto de workspace antes de processar qualquer requisição. O contexto de IA é escopado apenas a contatos e conversas dentro do workspace do chamador.

## Mapeamento de Conformidade

| Padrão    | Controle                                                  | Implementação                                                                       |
| --------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| ISO 27001 | A.9.1 — Política de controle de acesso                    | Acesso escopado por workspace aplicado na camada de API                             |
| ISO 27001 | A.9.4 — Controle de acesso a sistemas e aplicações        | `requireSettingsAccess()` em todas as rotas de configurações                        |
| GDPR      | Art.25 — Proteção de dados desde a concepção e por padrão | Isolamento de workspace por padrão; sem vazamento de dados entre tenants por design |
| GDPR      | Art.32 — Segurança do tratamento                          | Medidas técnicas que impedem o acesso não autorizado entre workspaces               |
| SOC 2     | CC6.1 — Controles de acesso lógico e físico               | Participação em workspace aplicada no servidor                                      |
| SOC 2     | CC6.2 — Anterior à emissão de credenciais de sistema      | Modelo somente por convite; credenciais emitidas apenas por ação explícita de admin |

<Tip>
  Para o mapeamento completo de controles de conformidade, veja a [Matriz de Conformidade](/pt-BR/security/compliance-matrix).
</Tip>
