Skip to content

Latest commit

 

History

History
744 lines (689 loc) · 22.1 KB

File metadata and controls

744 lines (689 loc) · 22.1 KB

Documentação da API - InsightPop (v1)

Nota de Infraestrutura: A partir da versão 0.4.1, o backend exige a presença estrita de variáveis de ambiente vitais (GEMINI_API_KEYS, SECRET_KEY, MONGO_URI) validadas via Pydantic. O servidor recusará a inicialização se o arquivo .env estiver incorreto ou incompleto.

Padrão Global de Erros: A partir da versão 0.5.1, todos os erros da API (HTTP 400, 401, 404, 409, 429, 500) retornam um objeto JSON padronizado no formato {"detail": "Mensagem descritiva do erro."}.

Developer Mock Mode: A API suporta um modo de testes enviando o cabeçalho X-Mock-Mode: true. Quando presente, os serviços de produção (Gemini) são substituídos por respostas fixas de mock, e a validação de data de expiração do JWT é ignorada, permitindo simulações locais sem consumir cotas.

Esta é a referência técnica completa de todos os endpoints disponíveis no backend FastAPI (/api/v1). Todos os retornos e requisições (exceto upload de arquivos) utilizam o formato application/json.

Índice


🔐 Autenticação e Conta (/auth)

Aviso de Segurança (JWT): A maioria dos endpoints desta API (com exceção das rotas abertas como /auth/signup e /auth/token) requerem autenticação via token JWT. Você deve incluir o cabeçalho Authorization: Bearer <seu_token> nas requisições protegidas.

POST /auth/signup

Registra um novo usuário e retorna um token de acesso JWT. Fatos de perfil e regras iniciais sugeridas também são salvos. Este endpoint possui limitação de taxa (Rate Limiting) por IP.

  • Payload Esperado:

    {
      "email": "usuario@exemplo.com",
      "password": "senha_super_segura",
      "profile_facts": [ // Pode ser lista vazia
        {
          "key": "Nome Completo",
          "value": "Maria da Silva"
        }
      ],
      "suggested_rules": [ // Opcional
        "Sempre me lembre de retornos 2 dias após orçamento."
      ]
    }
  • Retornos:

    • 201 (Sucesso):
      {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5c...",
        "token_type": "bearer"
      }
    • 400 (Erro - Email duplicado):
      {
        "detail": "Este email já está cadastrado."
      }
    • 422 (Erro - Validação):
      {
        "detail": [
          {
            "loc": ["body", "email"],
            "msg": "value is not a valid email address",
            "type": "value_error.email"
          }
        ]
      }
    • 429 (Erro - Rate Limit Excedido):
      {
        "detail": "Rate limit exceeded: 5 per 1 minute"
      }
    • 500 (Erro Interno):
      {
        "detail": "Internal Server Error"
      }

POST /auth/token

Autentica o usuário validando a senha e retorna um token de acesso JWT.

  • Payload Esperado: application/x-www-form-urlencoded

  • Retornos:

    • 200 (Sucesso):
      {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5c...",
        "token_type": "bearer"
      }
    • 401 (Erro - Credenciais inválidas):
      {
        "detail": "Email ou senha incorretos."
      }
    • 422 (Erro - Validação):
      {
        "detail": [
          {
            "loc": ["body", "password"],
            "msg": "field required",
            "type": "value_error.missing"
          }
        ]
      }

PUT /auth/profile

Atualiza o perfil de um usuário existente e salva regras adicionais caso informadas.

  • Payload Esperado:

    {
      "email": "usuario@exemplo.com",
      "profile_facts": [
        {
          "key": "Telefone",
          "value": "11999999999"
        }
      ],
      "suggested_rules": [] // Opcional (novas regras a serem adicionadas)
    }
  • Retornos:

    • 200 (Sucesso):
      {
        "message": "Profile updated successfully",
        "user": {
          "id": "65b9c1f2e1a2b3c4d5e6f7a8",
          "email": "usuario@exemplo.com",
          "profile_facts": [
            {
              "key": "Telefone",
              "value": "11999999999"
            }
          ]
        }
      }
    • 404 (Erro - Usuário não encontrado):
      {
        "detail": "User not found."
      }
    • 422 (Erro - Validação):
      {
        "detail": [
          {
            "loc": [
              "body",
              "profile_facts",
              0,
              "key"
            ],
            "msg": "field required",
            "type": "value_error.missing"
          }
        ]
      }

POST /auth/forgot-password

Solicita a recuperação de senha enviando um e-mail com um link seguro.

  • Payload Esperado:

    {
      "email": "usuario@exemplo.com"
    }
  • Retornos:

    • 200 (Sucesso):
      {
        "message": "Se o email estiver cadastrado, um link de recuperação foi enviado."
      }

POST /auth/reset-password

Define uma nova senha utilizando um token de recuperação válido.

  • Payload Esperado:

    {
      "token": "eyJhbGciOiJIUzI1NiIs...",
      "new_password": "nova_senha_segura"
    }
  • Retornos:

    • 200 (Sucesso):
      {
        "message": "Senha redefinida com sucesso."
      }
    • 400/401 (Erro - Token inválido ou expirado):
      {
        "detail": "Token inválido ou expirado."
      }

DELETE /auth/account

Exclui permanentemente a conta do usuário logado e todos os dados associados (regras e insights).

  • Cabeçalhos Exigidos:
    • Authorization: Bearer <seu_jwt_token>
  • Retornos:
    • 200 (Sucesso):
      {
        "message": "Conta e todos os dados associados foram excluídos com sucesso."
      }
    • 401 (Erro):
      {
        "detail": "Could not validate credentials"
      }

💬 Onboarding Conversacional (/onboarding)

GET /onboarding/start

Inicia o processo de onboarding, retornando a mensagem de boas-vindas do assistente virtual. Este endpoint possui limitação de taxa (Rate Limiting) por IP.

  • Payload Esperado: Nenhum.

  • Retornos:

    • 200 (Sucesso):
      {
        "message": "Olá! Sou a IA do InsightPop..."
      }
    • 429 (Erro - Rate Limit Excedido):
      {
        "detail": "Rate limit exceeded: 5 per 1 minute"
      }
    • 500 (Erro Interno):
      {
        "detail": "Failed to start onboarding."
      }

POST /onboarding/message

Envia o histórico do bate-papo para o Gemini analisar o perfil do usuário de forma contínua.

  • Payload Esperado:

    {
      "history": [
        {
          "role": "assistant",
          "content": "Olá! Como posso ajudar você hoje?"
        },
        {
          "role": "user",
          "content": "Sou arquiteto e gostaria de organizar meus projetos."
        }
      ]
    }
  • Retornos:

    • 200 (Caso 1 - Conversa continua):
      {
        "type": "chat",
        "message": "Que legal! E quais são os dados mais importantes para você?"
      }
    • 200 (Caso 2 - A decide que tem dados suficientes ou usuário encerra):
      {
        "type": "profile",
        "profile_facts": [
          {
            "key": "Profissão",
            "value": "Arquiteto"
          }
        ],
        "suggested_rules": [
          "Priorizar extração de orçamentos e prazos de projeto"
        ]
      }
    • 400 (Erro - Histórico vazio):
      {
        "detail": "Chat history cannot be empty."
      }
    • 500 (Erro Interno):
      {
        "detail": "Failed to process chat onboarding."
      }

🧠 Processamento e Extração de IA (/process)

POST /process

Recebe um arquivo desestruturado, envia para a IA (Google Gemini) e retorna os dados estruturados em JSON. (Nota: Usa um algoritmo determinístico de Smart Scoring que garante alta disponibilidade alternando chaves e modelos em milissegundos). Este endpoint possui limitação de taxa (Rate Limiting) por IP.

  • Payload Esperado: Requisição do tipo multipart/form-data contendo um campo file (Obrigatório). Suporta .txt, arquivos .zip (exportações do WhatsApp), Imagens (.png, .jpg) ou PDFs (.pdf).

  • Retornos:

    • 200 (Sucesso):
      {
        "context": "Professional",
        "title": "Orçamento Cliente X",
        "relevant_facts": [
          {
            "key": "Nome",
            "value": "João Carlos"
          }
        ],
        "action_triggers": [
          {
            "description": "Enviar proposta em PDF",
            "status": "pending",
            "date": "2026-03-01"
          }
        ],
        "first_contact_date": "2026-02-25",
        "last_contact_date": "2026-02-25"
      }
    • 400 (Erro - Tipo de arquivo não suportado):
      {
        "detail": "Unsupported file type: application/vnd.ms-excel."
      }
    • 429 (Erro - Rate Limit Excedido):
      {
        "detail": "Rate limit exceeded: 2 per 1 minute"
      }
    • 500 (Erro Interno):
      {
        "detail": "Erro interno ao processar resposta do Gemini."
      }

📚 Gestão de Insights / Memórias (/insights & /confirm-insights)

POST /confirm-insights

Endpoint principal (e central) para salvar, editar ou fundir memórias. Contém lógica interna de checagem de duplicidade por identificadores (CPF, Email, Telefone) para evitar registros repetidos.

Este endpoint atende a três fluxos distintos do aplicativo dependendo dos parâmetros enviados no payload:

  1. Criação de Nova Memória: Não envia consolidate_id nem remove_ids. O backend cria um novo registro (ou avisa sobre possível duplicidade se force_create for falso).
  2. Edição de Memória Existente: Envia o ID da memória que está sendo editada no campo consolidate_id. O backend sobrescreve os dados do banco de dados com os dados recebidos neste payload.
  3. Consolidação/Mesclagem de Memórias: Envia o ID da memória "Principal" no campo consolidate_id e uma lista de IDs das memórias secundárias no campo remove_ids. O backend sobrescreve a memória principal com os dados do payload e apaga as memórias secundárias listadas.
  • Payload Esperado:

    {
      "context": "Professional",
      "title": "Orçamento de Projeto", // Opcional
      "relevant_facts": [
        {
          "key": "Cliente",
          "value": "João"
        }
      ],
      "action_triggers": [
        {
          "description": "Ligar",
          "status": "pending"
        }
      ], // Obrigatório (pode ser vazio)
      "user_id": "65ba9c1f2e1a2b3c4d5e6f7a8",
      "first_contact_date": "2026-02-25", // Opcional
      "last_contact_date": "2026-02-25", // Opcional
      "force_create": false, // Opcional (Default: false)
      "consolidate_id": "65b9c1f2e1a2b3c4d5e6f7a8", // Opcional (ID para atualizar registro específico em casos de Edição/Consolidação)
      "remove_ids": ["65c1c1f2e1a2b3c4d5e6f7a8"], // Opcional (IDs para deletar após consolidação)
      "ignored_ids": ["65d3c1f2e1a2b3c4d5e6f7a8"] // Opcional (IDs de registros similares que o usuário escolheu NÃO mesclar)
    }
  • Retornos:

    • 201 (Sucesso - Criado/Atualizado):
      {
        "message": "Informações salvas como uma nova memória.",
        "id": "65b9c1f2e1a2b3c4d5e6f7a8",
        "created": true
      }
    • 201 (Caso 2 - Match Automático detectado pela IA):
      {
        "status": "potential_match",
        "message": "Encontrei uma memória similar...",
        "existing_record": {
           "id": "65b9c1f2e1a2b3c4d5e6f7a8",
           "title": "Cliente Antigo",
           "context": "Professional",
           "relevant_facts": [
             {
               "key": "Cliente",
               "value": "João Antigo"
             }
           ],
           "last_contact": "2026-02-24"
        }
      }
    • 404 (Erro - Não encontrado):
      {
        "detail": "Memória não encontrada ou já foi excluída."
      }
    • 422 (Erro - Validação):
      {
        "detail": [
          {
            "loc": ["body", "user_id"],
            "msg": "field required",
            "type": "value_error.missing"
          }
        ]
      }
    • 500 (Erro Interno):
      {
        "detail": "An error occurred during database operation: ..."
      }

GET /insights

Lista todas as memórias.

  • Payload Esperado: Nenhum.

  • Query Params Esperados:

    • user_id (String, Obrigatório): O ID do usuário dono dos insights.
    • workspace (String, Obrigatório): Filtra por contexto ("Personal" ou "Professional").
    • search (String, Opcional): Busca textual global que varre Títulos (title), chaves e valores dos Fatos (relevant_facts), e descrições de Tarefas (action_triggers), ignorando acentos e case-sensitive.
  • Retornos:

    • 200 (Sucesso):
      [
        {
          "_id": "65b9c1f2e1a2b3c4d5e6f7a8",
          "context": "Personal",
          "title": "Exame Médico",
          "relevant_facts": [
            {
              "key": "Médico",
              "value": "Dr. Silva"
            }
          ],
          "action_triggers": [
            {
              "description": "Retornar em 30 dias",
              "status": "pending",
              "date": "2026-03-30"
            }
          ],
          "user_id": "65ba9c1f2e1a2b3c4d5e6f7a8",
          "first_contact_date": "2026-02-25",
          "last_contact_date": "2026-02-25"
        }
      ]
    • 422 (Erro - Parâmetros ausentes):
      {
        "detail": [
          {
            "loc": ["query", "workspace"],
            "msg": "field required",
            "type": "value_error.missing"
          }
        ]
      }

GET /insights/count

Retorna a contagem total de memórias de um usuário.

  • Payload Esperado: Nenhum.
  • Query Params Esperados:
    • user_id (String, Obrigatório): O ID do usuário dono dos insights.
  • Retornos:
    • 200 (Sucesso): 15

GET /insights/{insight_id}

Retorna os detalhes de uma memória específica pelo seu ID.

  • Payload Esperado: Nenhum.
  • Retornos:
    • 200 (Sucesso):
      {
        "_id": "65b9c1f2e1a2b3c4d5e6f7a8",
        "context": "Personal",
        "title": "Exame Médico",
        "relevant_facts": [],
        "action_triggers": [],
        "user_id": "65ba9c1f2e1a2b3c4d5e6f7a8"
      }
    • 404 (Erro - Não encontrado):
      {
        "detail": "Insight not found."
      }

POST /insights/{insight_id}/snooze

Reagenda a data de um gatilho de ação específico dentro de uma memória.

  • Payload Esperado:
    {
      "days": 1, // Quantidade de dias para adiar
      "trigger_index": 0 // Posição do gatilho no array `action_triggers`
    }
  • Retornos:
    • 200 (Sucesso): {"message": "Action trigger snoozed successfully", "new_date": "2026-03-26"}
    • 400 (Erro - Índice inválido): {"detail": "Invalid trigger index"}
    • 404 (Erro - Não encontrado): {"detail": "Insight not found"}

DELETE /insights/{insight_id}/triggers/{trigger_index}

Remove permanentemente um gatilho de ação específico dentro de uma memória.

  • Retornos:
    • 200 (Sucesso): {"message": "Action trigger deleted successfully"}
    • 400 (Erro - Índice inválido): {"detail": "Invalid trigger index"}
    • 404 (Erro - Não encontrado): {"detail": "Insight not found"}

DELETE /insights/{insight_id}

Apaga uma memória permanentemente.

  • Retornos:
    • 204 (Sucesso): No Content
    • 404 (Erro - Não encontrado):
      {
        "detail": "Insight not found."
      }

POST /insights/preview-merge

Gera uma unificação virtual entre um registro existente no banco e novos dados vindos de uma edição ou upload recente, sem persistir nenhuma alteração.

  • Payload Esperado:
    {
      "primary_id": "65b9c1f2e1a2b3c4d5e6f7a8",
      "secondary_data": {
        "title": "Novo Título",
        "relevant_facts": [
          {
            "key": "Cargo",
            "value": "Gerente"
          }
        ],
        "action_triggers": [
          {
            "description": "Ligar amanhã",
            "date": "2026-03-03"
          }
        ],
        "user_id": "65ba9c1f2e1a2b3c4d5e6f7a8"
      }
    }
  • Retornos:
    • 200 (Sucesso):
      {
        "title": "Novo Título",
        "relevant_facts": [
          {
            "key": "Cargo",
            "value": "Gerente"
          }
        ],
        "action_triggers": [
          {
            "description": "Ligar amanhã",
            "date": "2026-03-03"
          }
        ],
      }
    • 404 (Erro - Registro primário não encontrado):
      {
        "detail": "Primary record not found."
      }

⚙️ Regras do Usuário (/rules)

GET /rules

Lista todas as diretrizes cadastradas. Requer user_id como Query Param. Payload Esperado: Nenhum.

  • Retornos:
    • 200 (Sucesso):
      [
        {
          "id": "65ba9c1f2e1a2b3c4d5e6f7a8",
          "name": "Ignorar Valores",
          "description": "Nunca extraia dinheiro",
          "trigger_keywords": ["R$", "preço"],
          "user_id": "65ba9c1f2e1a2b3c4d5e6f7a8"
        }
      ]
    • 422 (Erro - Parâmetros ausentes):
      {
        "detail": [
          {
            "loc": ["query", "user_id"],
            "msg": "field required",
            "type": "value_error.missing"
          }
        ]
      }

POST /rules

Cria uma nova regra para a IA.

  • Payload Esperado:

    {
      "name": "Nova Regra",
      "description": "Sempre extraia datas de vencimento",
      "trigger_keywords": ["vencimento", "pagar"],
      "user_id": "65ba9c1f2e1a2b3c4d5e6f7a8"
    }
  • Retornos:

    • 201 (Sucesso):
      {
        "id": "65bb9c1f2e1a2b3c4d5e6f7a8",
        "name": "Nova Regra",
        "description": "Descrição detalhada do comportamento desejado",
        "trigger_keywords": [
          "palavra1",
          "palavra2"
        ],
        "user_id": "id_usuario"
      }
    • 409 (Erro - Regra já existe):
      {
        "detail": "Another rule with this name already exists."
      }

PUT /rules/{rule_id}

Substitui completamente os dados de uma regra.

  • Payload Esperado:

    {
      "name": "Nome da Regra Atualizado",
      "description": "Nova descrição detalhada",
      "trigger_keywords": [
        "nova_palavra"
      ],
      "user_id": "id_usuario"
    }
  • Retorno 200 (Sucesso):

    {
      "id": "65bb...",
      "name": "Nome da Regra Atualizado",
      "description": "Nova descrição detalhada",
      "trigger_keywords": [
        "nova_palavra"
      ],
      "user_id": "id_usuario"
    }
  • Retorno 404 (Erro - Não encontrado):

    {
      "detail": "Rule not found."
    }

DELETE /rules/{rule_id}

Apaga uma regra.

  • Payload Esperado: Nenhum.

  • Retorno 204 (Sucesso): No Content (Corpo vazio).

  • Retorno 404 (Erro - Não encontrado):

    {
      "detail": "Rule not found."
    }