GitHunt

Solucione

Sumário

  1. Sobre o Projeto
  2. Tecnologias
  3. Funcionalidades
  4. Endpoints
  5. Demonstração
  6. Como Executar o Projeto
  7. Contato

Sobre o Projeto

Projeto desenvolvido para a disciplina de UPX - Usina de Projetos Experimentais IV, pertencente ao curso EAD de Análise e Desenvolvimento de Sistemas do Centro Universitário Facens.

A Solucione é uma plataforma de envio de reclamações relacionadas à infraestrutura, meio ambiente e mobilidade urbana. O projeto tem como ideia atuar em conjunto com as prefeituras, oferecendo um canal adicional e mais acessível para o registro dessas demandas.

Esta aplicação foi desenvolvida com Next.js para o backend e frontend. Utiliza um container Docker com PostgreSQL para o banco de dados, Prisma como ORM e R2 da Cloudflare para armazenamento de imagens.


Tecnologias

💻 Desenvolvimento
  • AWS SDK → Conjunto de ferramentas da Amazon utilizado na interação com buckets da R2 Cloudflare.
  • bcryptjs → Utilizado para realizar o hash seguro das senhas dos usuários.
  • Docker → Sistema de containers utilizado para criar e executar o banco de dados PostgreSQL de forma isolada.
  • framer-motion → Animações e transições suaves aplicadas na interface.
  • Google - API Gemini → Análise e validação de conteúdo.
  • Next.js → Framework React.js utilizado na construção de toda estrutura do frontend e das rotas de API.
  • React TanStack Query → Biblioteca utilizada no gerenciamento de estado de dados assíncronos.
  • Resend → Envio de e-mails para verificação de e-mail e confirmação do cadastro.
  • shadcn/ui → Conjunto de componentes acessíveis e performáticos.
  • Tailwind CSS → Framework CSS utilizado na estilização dos componentes e páginas.
  • TypeScript → Linguagem de programação fortemente tipada baseada em Javascript. Utilizada no desenvolvimento do projeto.
  • Zod + React Hook Form → Validação e gerenciamento de formulários.
🗄️ Banco de Dados
  • Cloudflare R2 → Banco de dados de objetos, utilizado no armazenamento das imagens.
  • PostgreSQL → Banco de dados relacional, utilizado no armazenamento das informações dos usuários e das reclamações.
  • Prisma → ORM (Object-Relational Mapper) utilizado na manipulação de dados e na interação com bancos de dados.
✨ Alinhamento e qualidade de código
  • ESLint → Ferramenta de linting para garantir a qualidade do código e encontrar problemas.
  • Prettier → Ferramenta de formatação de código para manter o estilo consistente.

Funcionalidades

  • Cadastro de usuário com verificação de e-mail: Permite o cadastro de novos usuários mediante verificação de e-mail.
  • Login e autenticação de usuários: Permite que os usuários façam login com credenciais e acessem a plataforma de forma segura.
  • Logout de usuários: Desfaz a autenticação, encerrando a sessão do usuário na aplicação.
  • Listagem de reclamações: Exibe na tela inicial todas as reclamações registradas na plataforma.
  • Detalhes de reclamação: Apresenta informações detalhadas sobre uma reclamação específica.
  • Criação de reclamações: Permite que os usuários registrem novas reclamações no sistema.
  • Atualização de status das reclamações: Permite que administradores alterem o status das ocorrências.
  • Validação de conteúdo impróprio: Utiliza a inteligência artificial do Google Gemini para detectar e bloquear conteúdo ofensivo ou inadequado em texto e imagens.
  • Mudança de tema: Oferece a opção de alternar entre temas claro e escuro para melhorar a experiência do usuário.

Endpoints

Abaixo você pode conferir um detalhamento dos endpoints utilizados no projeto. Para realizar as requisições HTTP e consultar o comportamento de cada endpoint, você pode utilizar a extensão Thunder Client.

⚠️ As URLs abaixo consideram que o projeto está rodando na porta 3000. Tenha isso em mente ao testar as rotas.

Occurrences

GET /occurrences

  • Retorna todas as reclamações registradas no banco de dados.
  • URL: http://localhost:3000/api/occurrences
  • Exemplo de retorno bem-sucedido:
{
  "message": "Ocorrências encontradas",
  "data": [
    {
      "id": 2,
      "title": "Lâmpada queimada no parque",
      "description": "Uma das lâmpadas do poste no parque está queimada, deixando a área escura à noite.",
      "street": "Rua das Flores",
      "neighborhood": "Vila Nova",
      "zipCode": "56.812-350",
      "reference": "Próximo à esquina",
      "status": "Aberto",
      "image": "https://pub-192c7de9eb344c6b87b7ac901aa60c7e.r2.dev/lampada-queimada.jpg",
      "userId": 4,
      "createdAt": "2025-04-02T10:00:00.000Z",
      "updatedAt": "2025-04-24T23:02:13.781Z",
      "user": {
        "id": 4,
        "name": "Ana Moares",
        "email": "ana@example.com",
        "role": "user",
        "createdAt": "2025-04-24T23:02:13.781Z",
        "updatedAt": "2025-04-24T23:02:13.781Z"
      },
      "occurrenceReplies": []
    },
    {
      "id": 1,
      "title": "Vazamento de água na rua principal",
      "description": "Há um vazamento de água na calçada em frente ao supermercado.",
      "street": "Rua Principal",
      "neighborhood": "Centro",
      "zipCode": "25.689-420",
      "reference": "Em frente ao estacionamento da praça",
      "status": "Finalizado",
      "image": "https://pub-192c7de9eb344c6b87b7ac901aa60c7e.r2.dev/vazamento-agua.jpg",
      "userId": 3,
      "createdAt": "2025-04-01T12:00:00.000Z",
      "updatedAt": "2025-04-24T23:02:13.781Z",
      "user": {
        "id": 3,
        "name": "Carlos Santos",
        "email": "carlos@example.com",
        "role": "user",
        "createdAt": "2025-04-24T23:02:13.781Z",
        "updatedAt": "2025-04-24T23:02:13.781Z"
      },
      "occurrenceReplies": [
        {
          "id": 1,
          "description": "Problema localizado e o conserto foi agendado para amanhã.",
          "imageUrl": "",
          "userId": 2,
          "occurrenceId": 1,
          "occurrenceStatus": "Andamento",
          "createdAt": "2025-04-06T00:00:00.000Z",
          "updatedAt": "2025-04-24T23:02:13.781Z",
          "user": {
            "id": 2,
            "name": "Maria Oliveira",
            "email": "maria@example.com",
            "role": "admin",
            "createdAt": "2025-04-24T23:02:13.781Z",
            "updatedAt": "2025-04-24T23:02:13.781Z"
          }
        },
        {
          "id": 2,
          "description": "Após vazamento de água na rua principal, nossa equipe respondeu prontamente, localizou e reparou a fonte, com medidas preventivas para evitar recorrências. Priorizamos a rápida resolução para garantir o bem-estar da comunidade",
          "imageUrl": "https://pub-192c7de9eb344c6b87b7ac901aa60c7e.r2.dev/conserto-vazamento-agua.jpg",
          "userId": 2,
          "occurrenceId": 1,
          "occurrenceStatus": "Finalizado",
          "createdAt": "2025-04-08T00:00:00.000Z",
          "updatedAt": "2025-04-24T23:02:13.781Z",
          "user": {
            "id": 2,
            "name": "Maria Oliveira",
            "email": "maria@example.com",
            "role": "admin",
            "createdAt": "2025-04-24T23:02:13.781Z",
            "updatedAt": "2025-04-24T23:02:13.781Z"
          }
        }
      ]
    }
  ]
}

GET /occurrences/:id

  • Retorna a reclamação de acordo com o id passado no endpoint.
  • Exemplo de URL: http://localhost:3000/api/occurrences/4
  • Exemplo de retorno bem-sucedido:
{
  "message": "Ocorrência encontrada",
  "data": {
    "id": 4,
    "title": "Passeio com buracos na Avenida Central",
    "description": "Os buracos no passeio estão representando um perigo para os pedestres.",
    "street": "Rua das Árvores",
    "neighborhood": "Jardim Botânico",
    "zipCode": "98.145-710",
    "reference": "Próximo à escola",
    "status": "Aberto",
    "image": "https://pub-192c7de9eb344c6b87b7ac901aa60c7e.r2.dev/passeio-buracos.jpg",
    "userId": 3,
    "createdAt": "2025-04-04T15:00:00.000Z",
    "updatedAt": "2025-04-24T23:02:13.781Z",
    "user": {
      "id": 3,
      "name": "Carlos Santos",
      "email": "carlos@example.com",
      "password": "123456",
      "role": "user",
      "createdAt": "2025-04-24T23:02:13.781Z",
      "updatedAt": "2025-04-24T23:02:13.781Z"
    },
    "occurrenceReplies": []
  }
}

POST /occurrences

  • Cria uma nova reclamação.
  • URL: http://localhost:3000/api/occurrences
  • O corpo da requisição precisa estar no formato form. Segue abaixo exemplo dos campos de texto:
{
  "title": "Buraco na rua principal",
  "description": "Grande buraco na pista colocando em risco a segurança dos motoristas.",
  "street": "Avenida Central, 1234",
  "neighborhood": "Centro",
  "zipCode": "12345-678",
  "reference": "Próximo ao supermercado Central"
}
  • Para requisições do tipo form, arquivos geralmente possuem um campo específico de envio.
  • Exemplo de retorno bem-sucedido:
{
  message: 'Ocorrência criada!',
  data: {
    id: 6,
    title: 'Buraco na rua principal',
    description: 'Grande buraco na pista colocando em risco a segurança dos motoristas.',
    street: 'Avenida Central, 1234',
    neighborhood: 'Centro',
    zipCode: '12.345-678',
    reference: 'Próximo ao supermercado Central',
    status: 'Aberto',
    image: 'https://exemplo.com/imagens/ocorrencia-buraco.jpg',
    userId: 4,
    createdAt: 2025-04-28T23:44:17.896Z,
    updatedAt: 2025-04-28T23:44:17.896Z
  },
},
Replies

POST /replies

  • Cria uma nova atualização para uma reclamação.
  • URL: http://localhost:3000/api/replies
  • O corpo da requisição precisa estar no formato form. Segue abaixo exemplo dos campos de texto:
{
  "userId": "1",
  "description": "Problema localizado e serviço iniciado.",
  "occurrenceId": "2",
  "occurrenceStatus": "Aberto",
}
  • Para requisições do tipo form, arquivos geralmente possuem um campo específico de envio.
  • Exemplo de retorno bem-sucedido:
{
  message: 'Atualização criada!',
  data: {
    id: 8,
    description: 'O problema foi resolvido e medidas preventivas foram implementadas.',
    imageUrl: '',
    userId: 1,
    occurrenceId: 3,
    occurrenceStatus: 'Finalizado',
    createdAt: 2025-05-29T21:48:56.956Z,
    updatedAt: 2025-05-29T21:48:56.956Z
  },
},

Demonstração

Você pode testar a aplicação através do link abaixo. Use as credenciais fornecidas para acessar com permissões de usuário comum ou administrador:

https://solucione-upx-iv.vercel.app

🔐 Credenciais de Teste

Usuário comum

Administrador

⚠️ Os dados cadastrados neste ambiente são públicos e podem ser restaurados a qualquer momento. Não insira informações sensíveis.


Como Executar o Projeto

Para rodar o projeto localmente, siga os passos abaixo.

  1. Verifique se a sua máquina possui as configurações mínimas para execução do projeto:
  • Sistema Operacional Distribuição Unix (Linux/macOS);
  • Node versão igual ou superior à 20.0.0 LTS;
  • Docker versão igual ou superior à 24.0.0;
  • Docker Compose versão igual ou superior à 2.20.0.
  1. Verifique se possui os elementos necessários dos serviços abaixo:
  • API key do Google Gemini;
  • API key do Resend;
  • Bucket criado no Cloudflare R2.
  1. Clone o repositório:
git clone git@github.com:garciaagui/solucione-upx-iv.git
  1. Navegue até a raiz do projeto:
cd solucione-upx-iv/
  1. Instale as dependências com o comando abaixo:
npm install
  1. Execute o comando abaixo para subir o container do banco de dados. Ao fazê-lo, o container project_upx_db será inicializado:
docker compose up
  1. Execute o comando abaixo para criar e aplicar as migrations no banco de dados. Ao fazê-lo, o banco será atualizado conforme o esquema definido no Prisma:
npx prisma migrate dev
  1. Preencha as variáveis de ambiente do arquivo .env
  • ⚠️ O valor padrão associado à variável RESEND_EMAIL no .env.example utiliza o domínio gratuito oferecido pelo Resend: @resend.dev. Com ele, só é possível enviar e-mails ao endereço de e-mail associado à sua conta Resend. Para fins de teste, é suficiente.
  1. Inicie a aplicação:
npm run dev
  1. No navegador, visite http://localhost:3000. Se tudo ocorreu bem, será possível utilizar a aplicação.

Contato

Projeto desenvolvido por Guilherme Garcia. Seguem abaixo minhas redes sociais e meios de contato. 🤘

Gmail
Linkedin
GitHub
Instagram

Voltar ao topo

garciaagui/solucione-upx-iv | GitHunt