AI Connect/Integration/Padrões Multi-Tenant

Padrões Multi-Tenant

Pergunte à IA sobre a Vinkius

Um único cliente com escopo na aplicação, escopo resolvido antes da entrada da requisição, capacidades retornadas apenas para o usuário autenticado e uma fronteira de isolamento que você pode testar.

Um único cliente Vinkius atende todos os usuários da sua aplicação. O isolamento vem de como você deriva o externalId, não de instâncias de cliente. Esta página é o checklist de segurança para integrar o SDK a um backend multi-tenant.

A Vinkius nunca encontra os seus usuários reais. A plataforma conhece a sua Application e o identificador opaco que o seu backend repassa, nada além disso. E-mails, nomes e perfis ficam nos seus sistemas; a Vinkius vê apenas o escopo do usuário que o seu código resolveu.

Crie um cliente com escopo na aplicação

typescript
// lib/vinkius.ts — server only
import { Vinkius } from '@vinkius/connect';

export const vinkius = new Vinkius({
  appId: process.env.VINKIUS_APP_ID!,
  apiKey: process.env.VINKIUS_APP_KEY!,
});

O cliente mantém credenciais da aplicação, nunca estado por usuário. Não construa um cliente por usuário; o escopo do usuário viaja na rota.

Resolva o escopo antes de ler a entrada da requisição

Vincule o externalId à sua sessão autenticada antes de qualquer outra coisa. A fronteira de autorização é a sua consulta de sessão; um App ID e uma chave autorizam a aplicação, nunca um usuário do navegador:

typescript
async function handleCapabilities(request: Request) {
  const session = await requireSession(request); // your auth code
  const capabilities = await vinkius.user(session.userId).capabilities();
  // ...
}

Retorne apenas as capacidades do usuário autenticado

Projete apenas os campos de que o seu cliente precisa e nada mais. Os objetos de capacidade já têm o escopo do usuário resolvido pela sessão:

typescript
return Response.json(
  capabilities.map(({ name, description, inputSchema }) => ({
    name,
    description,
    inputSchema,
  })),
);

Autorize a configuração do conector separadamente

Gravar credenciais é uma operação privilegiada. Verifique que a sessão tem permissão para administrar o conector daquele usuário antes de chamar connect() e credentials.set():

typescript
const github = vinkius.user(session.userId).connector('github');
await github.connect();
await github.credentials.set({ GITHUB_TOKEN: submittedToken });

Execute apenas capacidades carregadas no mesmo escopo

As capacidades carregam a rota de conexão que as produziu. Nunca aceite um nome de capacidade do cliente e o execute contra um handle resolvido de outro escopo; carregue o conjunto de capacidades dentro da requisição autenticada e despache a partir dele:

typescript
const capabilities = await vinkius.user(session.userId).capabilities();
const capability = capabilities.findCapability(requestedName);
if (!capability) {
  return Response.json({ error: 'not available for this user' }, { status: 404 });
}
const result = await capability.execute(args, { idempotencyKey });

Use metadados somente para contexto não secreto da aplicação

user.ensure(metadata) executa o upsert do usuário e armazena contexto da aplicação, como nível de plano ou rótulos. Não é um cofre de credenciais; mantenha segredos nas credenciais de conectores, que são somente para escrita.

Teste a fronteira de isolamento

Dois usuários conectando o mesmo conector jamais devem ver o estado um do outro. Um formato mínimo de teste:

typescript
const alice = vinkius.user('alice_123');
const bob = vinkius.user('bob_456');

await alice.connector('github').connect();
const bobConnectors = await bob.connectors();

// bob's list must not contain alice's connection

Execute isso contra um ambiente de staging com o seu próprio App ID e chave. Consulte Authentication and scope para as regras de separação de ambientes.

Próximos passos