Skip to content

feat(ai): adicionar cota diária por usuário e proteção anti-flood no Ask ApplyWell #109

Open

Description

@hugoalves-dev

Contexto

O Ask ApplyWell utiliza Gemini (Google AI Studio) para o chat com SSE e ferramentas de consulta. Hoje é necessário proteger a cota compartilhada do provedor contra uso excessivo, rajadas de mensagens, múltiplas requisições simultâneas e retries sem controle.

Os limites do Gemini são aplicados por projeto, não individualmente por usuário. Portanto, limitar apenas o frontend não protege a API nem impede que um usuário esgote a capacidade de todos.

Relacionadas: #81 (chatbot), #87 (tratamento de 429/quota do provedor), #93 (memória/contexto).

Objetivo

Implementar cota diária por usuário autenticado + proteção anti-flood no backend, com limites configuráveis e observabilidade, impedindo novas chamadas ao Gemini antes de exceder o orçamento.

Escopo backend

  • Aplicar os controles no ponto central de entrada do Ask ApplyWell, antes de chamar o modelo, incluindo requests SSE, independentemente de quantas abas ou clientes estejam abertos.
  • Cota diária por usuário em número de mensagens/chamadas ao assistente (valor por configuração, com sugestão inicial de 30 mensagens/dia). Explicitar timezone e horário do reset; não confundir com o reset diário do Google.
  • Rate limit por usuário em janela curta (sugestão inicial: 5 solicitações/minuto), além de uma geração em andamento por usuário para evitar flood e corridas de execução.
  • Limite global configurável para proteger a chave/projeto Gemini compartilhado; garantir que o limite por usuário não seja a única barreira contra estouro de RPM/RPD/TPM do provedor.
  • Validação, reserva e contabilização atômicas no backend, seguras contra requests simultâneos e múltiplas instâncias. Preferir mecanismo simples usando a persistência já existente; não adicionar Redis apenas para isso sem justificativa.
  • Definir política para contabilização e estorno de tentativas bloqueadas, falhas antes de chamar o modelo, falhas do provedor e interrupções de streams. Nenhum erro deve permitir burlar a cota; bloqueios locais não devem consumir cota.
  • Limitar tamanho de prompt/contexto e, quando suportado, tokens de saída, para uma única solicitação não drenar os recursos. Registrar métricas de uso/tokens retornadas pelo Spring AI/Gemini, considerando tool-calls.
  • Bloquear novas solicitações ao alcançar a cota, sem atingir o Gemini. Retornar HTTP 429 com código de erro estável e Retry-After/horário de liberação quando possível; para SSE, manter contrato de erro estruturado já discutido em feat: expose Gemini 429 retry delay and failed-message retry state #87.
  • Disponibilizar informação de uso diário, limite, restante e próximo reset para exibição futura no frontend (endpoint autenticado ou contrato existente). Não expor consumo de outros usuários.
  • Logs e métricas de requests autorizadas, bloqueadas, em curso, tokens e erros 429 locais vs. 429 Gemini; nunca logar conteúdo sensível de prompts.
  • Adicionar configurações via propriedades/variáveis de ambiente (cotas, janela, concorrência, limite global, habilitação), documentadas para operação.

Critérios de aceite

  1. Um usuário que atinge o limite diário não consegue disparar chamadas adicionais ao Gemini até a renovação da cota.
  2. Rajadas, solicitações paralelas e diferentes sessões/abas não burlam os limites.
  3. Cota e limite global permanecem corretos em concorrência, reinícios e eventual escala horizontal.
  4. Rejeições retornam erro claro, estruturado e informação de quando tentar novamente, sem encerrar incorretamente uma geração já autorizada.
  5. Falhas de upstream e desconexões não criam consumo fantasma nem permitem bypass.
  6. Testes automatizados cobrem limite diário, reset, rate-limit, concorrência, global, isolamento por usuário, falhas e SSE.
  7. Os valores dos limites são ajustáveis em produção sem alteração de código.

Fora do escopo inicial

  • Planos pagos, cobrança, painel administrativo avançado ou limites diferentes por assinatura.
  • Alteração da UX do frontend nesta issue (apenas expor contrato para consumo posterior).

Referências

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions