Files

28 KiB

Documentação Técnica das APIs - OllaHubBackend

Visão Geral

O OllaHubBackend é uma API REST desenvolvida em Rust (Actix Web) que fornece gerenciamento de modelos Ollama, operações criptográficas, gerenciamento de usuários e comunicação em tempo real via WebSocket.

Base URL

  • Desenvolvimento: http://127.0.0.1:8080
  • Produção: [A definir]

Versões da API

  • V1 (Legado): Endpoints implementados diretamente no main.rs
  • V2 (Modular): Endpoints organizados em módulos (src/api/mod.rs) - Recomendado
  • Usuários V1: CRUD de usuários em /api/v1/users

Swagger UI

Documentação interativa disponível em: http://127.0.0.1:8080/docs


Autenticação

A API utiliza JWT (JSON Web Tokens) para autenticação. Endpoints protegidos requerem o header de autorização.

Como Autenticar

Authorization: Bearer <seu_token_jwt>

Endpoints Protegidos

Os seguintes caminhos requerem autenticação JWT:

  • /api/v1/* (todos os endpoints de usuários)
  • /v2/api/crypto/* (todas as operações de criptografia)
  • /v2/api/models/* (operações de modelos)

Endpoints Públicos

  • GET /health
  • GET /v2/health
  • GET /v2/api/ollama/check
  • POST /v2/api/ollama/install
  • WS /v2/ws (WebSocket)

Configuração JWT

A chave secreta JWT é configurada via variável de ambiente:

  • Variável: JWT_SECRET
  • Padrão (dev): changeme-dev-secret

Endpoints

Sistema / Health

GET /health

Verifica o status básico da API.

Autenticação: Não requerida

Resposta:

"ok"

Exemplo:

curl http://127.0.0.1:8080/health

GET /v2/health

Verifica o status da API V2.

Autenticação: Não requerida

Resposta:

{
  "status": "ok"
}

Exemplo:

curl http://127.0.0.1:8080/v2/health

Ollama - Instalação e Verificação

GET /v2/api/ollama/check

Verifica se o Ollama está instalado e acessível no sistema.

Autenticação: Não requerida

Resposta:

{
  "installed": true,
  "in_path": true,
  "version": "0.1.15",
  "service_running": true,
  "api_status": "reachable",
  "details": {
    "native_version": "ollama version is 0.1.15",
    "api_/api/version": "{\"version\":\"0.1.15\"}",
    "api_/api/tags": "{\"models\":[...]}",
    "security_antivirus_active": "false",
    "security_antivirus_instructions": "..."
  },
  "issues": []
}

Campos da Resposta:

  • installed (boolean): Se o Ollama está instalado
  • in_path (boolean): Se o binário está no PATH
  • version (string|null): Versão do Ollama
  • service_running (boolean): Se o serviço está rodando
  • api_status (string): "reachable", "unreachable" ou "degraded"
  • details (object): Detalhes técnicos da instalação
  • issues (array): Lista de problemas encontrados

Exemplo:

curl http://127.0.0.1:8080/v2/api/ollama/check

POST /v2/api/ollama/install

Inicia o processo de instalação automática do Ollama (se não estiver instalado) e garante que o serviço esteja rodando. O progresso é enviado via WebSocket.

Autenticação: Não requerida

Request Body (opcional):

{
  "method": "auto",
  "platform": "auto"
}

Resposta:

{
  "status": "started",
  "operation_id": "550e8400-e29b-41d4-a716-446655440000"
}

Campos da Resposta:

  • status (string): Status da operação ("started")
  • operation_id (string): UUID da operação para rastreamento via WebSocket

Eventos WebSocket:

  • Log: Mensagens de log durante a instalação
  • Progress: Progresso da instalação
  • Done: Instalação concluída com sucesso
  • Error: Erro durante a instalação

Exemplo:

curl -X POST http://127.0.0.1:8080/v2/api/ollama/install \
  -H "Content-Type: application/json" \
  -d '{"method": "auto", "platform": "auto"}'

Notas:

  • A instalação é específica por plataforma (Windows, Linux, macOS)
  • O progresso é enviado via WebSocket (WS /v2/ws)
  • Em caso de falha, eventos Error são enviados via WebSocket
  • Os endpoints V1 (GET /ollama/install-check e POST /ollama/install) foram removidos

Modelos (V2)

GET /v2/api/models

Lista todos os modelos disponíveis do arquivo modelList.json.

Autenticação: Requerida (JWT)

Resposta:

[
  {
    "name": "llama2",
    "description": "Modelo LLaMA 2"
  },
  {
    "name": "mistral",
    "description": "Modelo Mistral"
  }
]

Códigos de Status:

  • 200 OK: Sucesso
  • 401 Unauthorized: Token JWT inválido ou ausente
  • 500 Internal Server Error: Erro ao ler arquivo de modelos

Exemplo:

curl -H "Authorization: Bearer <token>" \
  http://127.0.0.1:8080/v2/api/models

JavaScript/TypeScript:

const response = await fetch('http://127.0.0.1:8080/v2/api/models', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});
const models = await response.json();

POST /v2/api/models/install

Inicia a instalação (download) de um modelo do Ollama. O progresso é enviado via WebSocket.

Autenticação: Requerida (JWT)

Request Body:

{
  "name": "llama2:7b"
}

Resposta:

{
  "status": "started",
  "model": "llama2:7b"
}

Códigos de Status:

  • 202 Accepted: Instalação iniciada
  • 400 Bad Request: Nome do modelo inválido
  • 401 Unauthorized: Token JWT inválido ou ausente
  • 500 Internal Server Error: Erro ao iniciar instalação

Exemplo:

curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"name":"llama2:7b"}' \
  http://127.0.0.1:8080/v2/api/models/install

JavaScript/TypeScript:

const response = await fetch('http://127.0.0.1:8080/v2/api/models/install', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'llama2:7b' })
});
const result = await response.json();

Notas:

  • O progresso da instalação é enviado via WebSocket (/v2/ws)
  • Conecte-se ao WebSocket antes de iniciar a instalação para receber eventos
  • O formato do nome pode incluir tag: "modelo:tag" (ex: "llama2:7b")

Criptografia (V2)

Todas as operações de criptografia usam AES-256-GCM com chave de 32 bytes.

POST /v2/api/crypto/set-key

Define a chave de criptografia (deve ser chamado antes de usar encrypt/decrypt).

Autenticação: Requerida (JWT)

Request Body:

{
  "hex_key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}

Resposta:

{
  "ok": true
}

Códigos de Status:

  • 200 OK: Chave definida com sucesso
  • 400 Bad Request: Chave inválida (deve ter 64 caracteres hex = 32 bytes)
  • 401 Unauthorized: Token JWT inválido ou ausente
  • 409 Conflict: Chave já foi definida anteriormente

Exemplo:

curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"hex_key":"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}' \
  http://127.0.0.1:8080/v2/api/crypto/set-key

Notas:

  • A chave é persistida no disco automaticamente
  • Use a mesma chave no frontend para operações de criptografia
  • A chave deve ter exatamente 64 caracteres hexadecimais (32 bytes)

POST /v2/api/crypto/rotate-key

Gera uma nova chave de criptografia aleatória e retorna em hexadecimal.

Autenticação: Requerida (JWT)

Resposta:

{
  "key": "a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef123456"
}

Códigos de Status:

  • 200 OK: Chave rotacionada com sucesso
  • 401 Unauthorized: Token JWT inválido ou ausente
  • 500 Internal Server Error: Erro ao gerar/salvar chave

Exemplo:

curl -X POST \
  -H "Authorization: Bearer <token>" \
  http://127.0.0.1:8080/v2/api/crypto/rotate-key

Notas:

  • A nova chave substitui a anterior
  • Salve a chave retornada para uso no frontend
  • A chave é automaticamente persistida no disco

POST /v2/api/crypto/encrypt

Criptografa dados usando AES-256-GCM.

Autenticação: Requerida (JWT)

Request Body:

{
  "data": "dados sensíveis para criptografar"
}

Resposta:

{
  "ciphertext": "base64_encoded_ciphertext_with_nonce"
}

Códigos de Status:

  • 200 OK: Criptografia bem-sucedida
  • 400 Bad Request: Chave não definida ou dados inválidos
  • 401 Unauthorized: Token JWT inválido ou ausente

Exemplo:

curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"data":"minha senha secreta"}' \
  http://127.0.0.1:8080/v2/api/crypto/encrypt

Notas:

  • O nonce (12 bytes) é incluído automaticamente no início do ciphertext
  • O resultado é retornado em Base64
  • O formato do ciphertext: [nonce 12 bytes][ciphertext] (tudo em Base64)

POST /v2/api/crypto/decrypt

Descriptografa dados usando AES-256-GCM.

Autenticação: Requerida (JWT)

Request Body:

{
  "data": "base64_encoded_ciphertext_with_nonce"
}

Resposta:

{
  "plaintext": "dados descriptografados"
}

Códigos de Status:

  • 200 OK: Descriptografia bem-sucedida
  • 400 Bad Request: Chave não definida, Base64 inválido ou tag de autenticação inválida
  • 401 Unauthorized: Token JWT inválido ou ausente

Exemplo:

curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"data":"ciphertext_base64_aqui"}' \
  http://127.0.0.1:8080/v2/api/crypto/decrypt

Notas:

  • O nonce é extraído automaticamente dos primeiros 12 bytes
  • O data deve ser o mesmo ciphertext retornado por encrypt
  • A tag de autenticação GCM é verificada automaticamente

Usuários (V1)

GET /api/v1/users

Lista todos os usuários cadastrados.

Autenticação: Requerida (JWT)

Resposta:

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "João Silva",
    "email": "[email protected]"
  },
  {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "name": "Maria Santos",
    "email": "[email protected]"
  }
]

Códigos de Status:

  • 200 OK: Sucesso
  • 401 Unauthorized: Token JWT inválido ou ausente

Exemplo:

curl -H "Authorization: Bearer <token>" \
  http://127.0.0.1:8080/api/v1/users

GET /api/v1/users/{id}

Obtém um usuário específico por ID.

Autenticação: Requerida (JWT)

Parâmetros de Path:

  • id (string): UUID do usuário

Resposta:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "João Silva",
  "email": "[email protected]"
}

Códigos de Status:

  • 200 OK: Usuário encontrado
  • 401 Unauthorized: Token JWT inválido ou ausente
  • 404 Not Found: Usuário não encontrado

Exemplo:

curl -H "Authorization: Bearer <token>" \
  http://127.0.0.1:8080/api/v1/users/550e8400-e29b-41d4-a716-446655440000

POST /api/v1/users

Cria um novo usuário.

Autenticação: Requerida (JWT)

Request Body:

{
  "name": "João Silva",
  "email": "[email protected]"
}

Validações:

  • name: Mínimo 2 caracteres
  • email: Formato de email válido

Resposta:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "João Silva",
  "email": "[email protected]"
}

Códigos de Status:

  • 201 Created: Usuário criado com sucesso
  • 400 Bad Request: Erro de validação
  • 401 Unauthorized: Token JWT inválido ou ausente

Exemplo:

curl -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"name":"João Silva","email":"[email protected]"}' \
  http://127.0.0.1:8080/api/v1/users

PUT /api/v1/users/{id}

Atualiza um usuário existente.

Autenticação: Requerida (JWT)

Parâmetros de Path:

  • id (string): UUID do usuário

Request Body:

{
  "name": "João Silva Atualizado",
  "email": "[email protected]"
}

Validações:

  • name: Mínimo 2 caracteres (opcional)
  • email: Formato de email válido (opcional)

Resposta:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "João Silva Atualizado",
  "email": "[email protected]"
}

Códigos de Status:

  • 200 OK: Usuário atualizado
  • 400 Bad Request: Erro de validação
  • 401 Unauthorized: Token JWT inválido ou ausente
  • 404 Not Found: Usuário não encontrado

Exemplo:

curl -X PUT \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"name":"João Silva Atualizado","email":"[email protected]"}' \
  http://127.0.0.1:8080/api/v1/users/550e8400-e29b-41d4-a716-446655440000

DELETE /api/v1/users/{id}

Remove um usuário.

Autenticação: Requerida (JWT)

Parâmetros de Path:

  • id (string): UUID do usuário

Resposta: Sem corpo (204 No Content)

Códigos de Status:

  • 204 No Content: Usuário removido
  • 401 Unauthorized: Token JWT inválido ou ausente
  • 404 Not Found: Usuário não encontrado

Exemplo:

curl -X DELETE \
  -H "Authorization: Bearer <token>" \
  http://127.0.0.1:8080/api/v1/users/550e8400-e29b-41d4-a716-446655440000

WebSocket (V2)

WS /v2/ws

Endpoint WebSocket para receber eventos em tempo real, especialmente durante a instalação de modelos.

Autenticação: Não requerida (mas pode ser implementada)

Conexão:

ws://127.0.0.1:8080/v2/ws

Tipos de Eventos:

  1. Log: Mensagens de log durante operações
{
  "kind": "Log",
  "message": "Downloading model llama2:7b..."
}
  1. Progress: Progresso de operações (ex: download de modelo)
{
  "kind": "Progress",
  "message": "{\"status\":\"downloading\",\"completed\":50,\"total\":100}"
}
  1. Done: Operação concluída
{
  "kind": "Done",
  "message": "Download do modelo 'llama2:7b' concluído"
}
  1. Error: Erro durante operação
{
  "kind": "Error",
  "message": "Falha ao conectar com API do Ollama"
}

Exemplo JavaScript:

const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws');

ws.onopen = () => {
  console.log('WebSocket conectado');
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Evento recebido:', data);
  
  switch(data.kind) {
    case 'Log':
      console.log('Log:', data.message);
      break;
    case 'Progress':
      console.log('Progresso:', data.message);
      break;
    case 'Done':
      console.log('Concluído:', data.message);
      break;
    case 'Error':
      console.error('Erro:', data.message);
      break;
  }
};

ws.onerror = (error) => {
  console.error('Erro WebSocket:', error);
};

ws.onclose = () => {
  console.log('WebSocket desconectado');
};

Exemplo TypeScript:

enum WsEventKind {
  Log = 'Log',
  Progress = 'Progress',
  Done = 'Done',
  Error = 'Error'
}

interface WsEvent {
  kind: WsEventKind;
  message: string;
}

const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws');

ws.onmessage = (event: MessageEvent) => {
  const data: WsEvent = JSON.parse(event.data);
  // Processar evento
};

Fluxo de Instalação de Modelo:

  1. Conecte-se ao WebSocket
  2. Chame POST /v2/api/models/install com o nome do modelo
  3. Receba eventos via WebSocket:
    • Log: Mensagens de progresso
    • Progress: Atualizações de progresso (se disponível)
    • Done: Instalação concluída
    • Error: Erro durante instalação

Notas:

  • O WebSocket mantém a conexão aberta para receber múltiplos eventos

WebSocket Chat (/v2/ws/chat)

Endpoint WebSocket dedicado para chat com modelos Ollama, oferecendo streaming em tempo real das respostas.

Conectar

const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws/chat');

ws.onopen = () => {
  console.log('Chat WebSocket conectado');
  
  // Enviar mensagem de chat
  const chatRequest = {
    model: "llama2",
    messages: [
      { role: "user", content: "Olá, como você está?" }
    ],
    stream: true,
    options: {
      temperature: 0.7,
      top_p: 0.9
    }
  };
  
  ws.send(JSON.stringify(chatRequest));
};

ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
  
  if (response.done) {
    console.log('Chat finalizado');
    return;
  }
  
  if (response.message) {
    // Acumular conteúdo da mensagem
    console.log('Chunk recebido:', response.message.content);
  }
  
  if (response.error) {
    console.error('Erro no chat:', response.error);
  }
};

ws.onerror = (error) => {
  console.error('Erro WebSocket chat:', error);
};

ws.onclose = () => {
  console.log('Chat WebSocket desconectado');
};

Formato da Requisição

{
  "model": "llama2",
  "messages": [
    { "role": "user", "content": "Sua mensagem aqui" },
    { "role": "assistant", "content": "Resposta anterior" }
  ],
  "stream": true,
  "options": {
    "temperature": 0.7,
    "top_p": 0.9,
    "top_k": 40
  }
}

Campos:

  • model (string, obrigatório): Nome do modelo a ser usado
  • messages (array, obrigatório): Array de mensagens no formato { role: "user"|"assistant", content: string }
  • stream (boolean, opcional): Sempre true para streaming (padrão: true)
  • options (object, opcional): Opções do modelo (temperature, top_p, top_k, etc.)

Formato da Resposta (Streaming)

Cada chunk recebido é um objeto JSON:

{
  "model": "llama2",
  "created_at": "2024-01-01T12:00:00Z",
  "message": {
    "role": "assistant",
    "content": "Olá! Estou bem, obrigado por perguntar."
  },
  "done": false
}

Último chunk (quando done: true):

{
  "model": "llama2",
  "created_at": "2024-01-01T12:00:05Z",
  "message": null,
  "done": true,
  "total_duration": 5000000000,
  "load_duration": 100000000,
  "prompt_eval_count": 10,
  "prompt_eval_duration": 200000000,
  "eval_count": 50,
  "eval_duration": 4700000000
}

Características

  • Streaming em tempo real: Respostas são enviadas chunk por chunk conforme geradas
  • Baixa latência: WebSocket mantém conexão persistente
  • Heartbeat: Ping/pong automático a cada 5 segundos
  • Timeout: Desconexão automática após 30 segundos de inatividade
  • Múltiplas conversas: Uma conexão pode enviar múltiplas requisições de chat

Exemplo Completo: Conversa com Histórico

const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws/chat');
let conversationHistory = [];

ws.onopen = () => {
  sendMessage("Olá!");
};

function sendMessage(userMessage) {
  // Adicionar mensagem do usuário ao histórico
  conversationHistory.push({ role: "user", content: userMessage });
  
  const request = {
    model: "llama2",
    messages: conversationHistory,
    stream: true
  };
  
  ws.send(JSON.stringify(request));
}

ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
  
  if (response.done) {
    // Adicionar resposta completa ao histórico
    if (response.message) {
      conversationHistory.push(response.message);
    }
    console.log('Conversa atualizada:', conversationHistory);
    return;
  }
  
  // Acumular chunks da resposta
  if (response.message && response.message.content) {
    process.stdout.write(response.message.content);
  }
};

// Enviar próxima mensagem após resposta completa
ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
  
  if (response.done) {
    if (response.message) {
      conversationHistory.push(response.message);
    }
    // Próxima mensagem do usuário
    sendMessage("Conte-me uma piada");
  } else if (response.message) {
    process.stdout.write(response.message.content);
  }
};

Tratamento de Erros

ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
  
  if (response.error) {
    console.error('Erro do Ollama:', response.error);
    // Erro pode ocorrer em qualquer chunk
  }
  
  if (response.done && response.error) {
    // Erro final - conexão pode ser fechada
    ws.close();
  }
};

Notas Importantes

  • O endpoint requer autenticação JWT (mesmo token usado em outras APIs)
  • O WebSocket mantém a conexão aberta para múltiplas requisições
  • Cada requisição deve incluir o histórico completo da conversa
  • Respostas são enviadas em formato JSON lines (uma linha por chunk)
  • Use done: true para saber quando a resposta está completa
  • Eventos são broadcast para todos os clientes conectados
  • Ping/Pong são gerenciados automaticamente

Modelos de Dados

User

interface User {
  id: string;        // UUID
  name: string;      // Mínimo 2 caracteres
  email: string;     // Email válido
}

CreateUserRequest

interface CreateUserRequest {
  name: string;      // Mínimo 2 caracteres
  email: string;     // Email válido
}

UpdateUserRequest

interface UpdateUserRequest {
  name?: string;     // Mínimo 2 caracteres (opcional)
  email?: string;    // Email válido (opcional)
}

ModelInfo

interface ModelInfo {
  name: string;
  description?: string;
}

InstallReq

interface InstallReq {
  name: string;      // Nome do modelo (ex: "llama2:7b")
}

SetKeyReq

interface SetKeyReq {
  hex_key: string;   // 64 caracteres hex (32 bytes)
}

CryptReq

interface CryptReq {
  data: string;      // Dados para criptografar/descriptografar
}

ApiErrorBody

interface ApiErrorBody {
  error: string;     // Mensagem de erro
}

WsEvent

enum WsEventKind {
  Log = 'Log',
  Progress = 'Progress',
  Done = 'Done',
  Error = 'Error'
}

interface WsEvent {
  kind: WsEventKind;
  message: string;
}

Tratamento de Erros

Códigos de Status HTTP

  • 200 OK: Requisição bem-sucedida
  • 201 Created: Recurso criado com sucesso
  • 202 Accepted: Requisição aceita para processamento assíncrono
  • 204 No Content: Sucesso sem conteúdo de retorno
  • 400 Bad Request: Erro na requisição (validação, formato)
  • 401 Unauthorized: Token JWT ausente ou inválido
  • 404 Not Found: Recurso não encontrado
  • 409 Conflict: Conflito (ex: chave já definida)
  • 500 Internal Server Error: Erro interno do servidor

Formato de Erro

Todos os erros retornam o seguinte formato:

{
  "error": "Mensagem de erro descritiva"
}

Exemplos de Erros

400 Bad Request:

{
  "error": "validação: email: deve ser um email válido"
}

401 Unauthorized:

{
  "error": "Token JWT inválido ou ausente"
}

404 Not Found:

{
  "error": "Usuário não encontrado"
}

500 Internal Server Error:

{
  "error": "Falha ao ler arquivo de modelos: No such file or directory"
}

Variáveis de Ambiente

OLLAMA_BASE_URL

  • Descrição: URL base da API do Ollama
  • Padrão: http://localhost:11434
  • Uso: Usado para comunicação com o Ollama

MODEL_LIST_PATH

  • Descrição: Caminho para o arquivo JSON com lista de modelos
  • Padrão: modelList.json
  • Uso: Arquivo lido para listar modelos disponíveis

JWT_SECRET

  • Descrição: Chave secreta para assinatura de tokens JWT
  • Padrão: changeme-dev-secret
  • Uso: Validação de tokens JWT
  • Importante:
    • Deve ser o mesmo valor usado no frontend para gerar tokens
    • Altere em produção!
    • Pode ser configurado via variável de ambiente ou arquivo .env

Configuração via .env (recomendado):

JWT_SECRET=5741f9da3be6007674a5e10edab7b124

Configuração via variável de ambiente:

# Windows (PowerShell)
$env:JWT_SECRET="5741f9da3be6007674a5e10edab7b124"

# Linux/Mac
export JWT_SECRET="5741f9da3be6007674a5e10edab7b124"

SKIP_ANTIVIRUS_WARNINGS

  • Descrição: Suprime avisos de verificação de antivírus durante inicialização
  • Padrão: false
  • Valores: true ou false
  • Uso: Define como true para desabilitar avisos informativos sobre antivírus/segurança
  • Exemplo: SKIP_ANTIVIRUS_WARNINGS=true cargo run

Exemplos de Fluxos Completos

Fluxo 1: Instalar um Modelo com Acompanhamento via WebSocket

// 1. Conectar ao WebSocket
const ws = new WebSocket('ws://127.0.0.1:8080/v2/ws');

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.kind === 'Done') {
    console.log('Modelo instalado!');
  }
};

// 2. Aguardar conexão
ws.onopen = async () => {
  // 3. Iniciar instalação
  const response = await fetch('http://127.0.0.1:8080/v2/api/models/install', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ name: 'llama2:7b' })
  });
  
  const result = await response.json();
  console.log('Instalação iniciada:', result);
};

Fluxo 2: Configurar Criptografia e Criptografar Dados

// 1. Definir chave (ou rotacionar)
const rotateResponse = await fetch('http://127.0.0.1:8080/v2/api/crypto/rotate-key', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

const { key } = await rotateResponse.json();
console.log('Nova chave:', key);

// 2. Criptografar dados
const encryptResponse = await fetch('http://127.0.0.1:8080/v2/api/crypto/encrypt', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ data: 'dados sensíveis' })
});

const { ciphertext } = await encryptResponse.json();
console.log('Dados criptografados:', ciphertext);

// 3. Descriptografar
const decryptResponse = await fetch('http://127.0.0.1:8080/v2/api/crypto/decrypt', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ data: ciphertext })
});

const { plaintext } = await decryptResponse.json();
console.log('Dados descriptografados:', plaintext);

Fluxo 3: CRUD Completo de Usuários

const baseUrl = 'http://127.0.0.1:8080/api/v1/users';
const headers = {
  'Authorization': `Bearer ${token}`,
  'Content-Type': 'application/json'
};

// 1. Criar usuário
const createResponse = await fetch(baseUrl, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    name: 'João Silva',
    email: '[email protected]'
  })
});
const newUser = await createResponse.json();
console.log('Usuário criado:', newUser);

// 2. Listar usuários
const listResponse = await fetch(baseUrl, { headers });
const users = await listResponse.json();
console.log('Usuários:', users);

// 3. Obter usuário específico
const getUserResponse = await fetch(`${baseUrl}/${newUser.id}`, { headers });
const user = await getUserResponse.json();
console.log('Usuário:', user);

// 4. Atualizar usuário
const updateResponse = await fetch(`${baseUrl}/${newUser.id}`, {
  method: 'PUT',
  headers,
  body: JSON.stringify({
    name: 'João Silva Atualizado',
    email: '[email protected]'
  })
});
const updatedUser = await updateResponse.json();
console.log('Usuário atualizado:', updatedUser);

// 5. Deletar usuário
await fetch(`${baseUrl}/${newUser.id}`, {
  method: 'DELETE',
  headers
});
console.log('Usuário deletado');

Notas Importantes

Segurança

  1. JWT Secret: Sempre altere o JWT_SECRET em produção
  2. HTTPS: Use HTTPS em produção para proteger tokens e dados
  3. Chave de Criptografia: Mantenha a chave de criptografia segura e nunca a exponha
  4. Validação: Todos os inputs são validados no backend

Performance

  1. WebSocket: Use WebSocket para operações longas (instalação de modelos)
  2. Assíncrono: Instalação de modelos é assíncrona (202 Accepted)
  3. Cache: Considere cachear lista de modelos no frontend

Compatibilidade

  1. V1 vs V2: Prefira endpoints V2 quando disponíveis
  2. Swagger: Use /docs para documentação interativa
  3. Versões: Endpoints V1 podem ser descontinuados no futuro

Limitações

  1. Armazenamento de Usuários: Atualmente em memória (perdido ao reiniciar)
  2. Chave de Criptografia: Uma chave por instância do servidor
  3. WebSocket: Broadcast para todos os clientes (não filtrado por operação)

Suporte e Recursos

  • Swagger UI: http://127.0.0.1:8080/docs
  • Health Check: http://127.0.0.1:8080/health
  • Código Fonte: Ver repositório do projeto

Última Atualização: 2024