# 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 ```http Authorization: Bearer ``` ### 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**: ```json "ok" ``` **Exemplo**: ```bash curl http://127.0.0.1:8080/health ``` --- #### GET /v2/health Verifica o status da API V2. **Autenticação**: Não requerida **Resposta**: ```json { "status": "ok" } ``` **Exemplo**: ```bash 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**: ```json { "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**: ```bash 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): ```json { "method": "auto", "platform": "auto" } ``` **Resposta**: ```json { "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**: ```bash 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**: ```json [ { "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**: ```bash curl -H "Authorization: Bearer " \ http://127.0.0.1:8080/v2/api/models ``` **JavaScript/TypeScript**: ```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**: ```json { "name": "llama2:7b" } ``` **Resposta**: ```json { "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**: ```bash curl -X POST \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"name":"llama2:7b"}' \ http://127.0.0.1:8080/v2/api/models/install ``` **JavaScript/TypeScript**: ```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**: ```json { "hex_key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" } ``` **Resposta**: ```json { "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**: ```bash curl -X POST \ -H "Authorization: Bearer " \ -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**: ```json { "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**: ```bash curl -X POST \ -H "Authorization: Bearer " \ 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**: ```json { "data": "dados sensíveis para criptografar" } ``` **Resposta**: ```json { "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**: ```bash curl -X POST \ -H "Authorization: Bearer " \ -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**: ```json { "data": "base64_encoded_ciphertext_with_nonce" } ``` **Resposta**: ```json { "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**: ```bash curl -X POST \ -H "Authorization: Bearer " \ -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**: ```json [ { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "João Silva", "email": "joao@example.com" }, { "id": "660e8400-e29b-41d4-a716-446655440001", "name": "Maria Santos", "email": "maria@example.com" } ] ``` **Códigos de Status**: - `200 OK`: Sucesso - `401 Unauthorized`: Token JWT inválido ou ausente **Exemplo**: ```bash curl -H "Authorization: Bearer " \ 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**: ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "João Silva", "email": "joao@example.com" } ``` **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**: ```bash curl -H "Authorization: Bearer " \ 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**: ```json { "name": "João Silva", "email": "joao@example.com" } ``` **Validações**: - `name`: Mínimo 2 caracteres - `email`: Formato de email válido **Resposta**: ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "João Silva", "email": "joao@example.com" } ``` **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**: ```bash curl -X POST \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"name":"João Silva","email":"joao@example.com"}' \ 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**: ```json { "name": "João Silva Atualizado", "email": "joao.novo@example.com" } ``` **Validações**: - `name`: Mínimo 2 caracteres (opcional) - `email`: Formato de email válido (opcional) **Resposta**: ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "João Silva Atualizado", "email": "joao.novo@example.com" } ``` **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**: ```bash curl -X PUT \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"name":"João Silva Atualizado","email":"joao.novo@example.com"}' \ 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**: ```bash curl -X DELETE \ -H "Authorization: Bearer " \ 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 ```json { "kind": "Log", "message": "Downloading model llama2:7b..." } ``` 2. **Progress**: Progresso de operações (ex: download de modelo) ```json { "kind": "Progress", "message": "{\"status\":\"downloading\",\"completed\":50,\"total\":100}" } ``` 3. **Done**: Operação concluída ```json { "kind": "Done", "message": "Download do modelo 'llama2:7b' concluído" } ``` 4. **Error**: Erro durante operação ```json { "kind": "Error", "message": "Falha ao conectar com API do Ollama" } ``` **Exemplo JavaScript**: ```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**: ```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 ```javascript 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 ```json { "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: ```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`): ```json { "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 ```javascript 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 ```javascript 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 ```typescript interface User { id: string; // UUID name: string; // Mínimo 2 caracteres email: string; // Email válido } ``` ### CreateUserRequest ```typescript interface CreateUserRequest { name: string; // Mínimo 2 caracteres email: string; // Email válido } ``` ### UpdateUserRequest ```typescript interface UpdateUserRequest { name?: string; // Mínimo 2 caracteres (opcional) email?: string; // Email válido (opcional) } ``` ### ModelInfo ```typescript interface ModelInfo { name: string; description?: string; } ``` ### InstallReq ```typescript interface InstallReq { name: string; // Nome do modelo (ex: "llama2:7b") } ``` ### SetKeyReq ```typescript interface SetKeyReq { hex_key: string; // 64 caracteres hex (32 bytes) } ``` ### CryptReq ```typescript interface CryptReq { data: string; // Dados para criptografar/descriptografar } ``` ### ApiErrorBody ```typescript interface ApiErrorBody { error: string; // Mensagem de erro } ``` ### WsEvent ```typescript 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: ```json { "error": "Mensagem de erro descritiva" } ``` ### Exemplos de Erros **400 Bad Request**: ```json { "error": "validação: email: deve ser um email válido" } ``` **401 Unauthorized**: ```json { "error": "Token JWT inválido ou ausente" } ``` **404 Not Found**: ```json { "error": "Usuário não encontrado" } ``` **500 Internal Server Error**: ```json { "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): ```env JWT_SECRET=5741f9da3be6007674a5e10edab7b124 ``` **Configuração via variável de ambiente**: ```bash # 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 ```javascript // 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 ```javascript // 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 ```javascript 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: 'joao@example.com' }) }); 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: 'joao.novo@example.com' }) }); 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