Eu aprendi a sintaxe do Ruby e o framework Ruby on Rails e desenvolvi este projeto em um período de 7 dias. Fiz tudo isso em lives no YouTube, e, ao longo desses 7 dias, realizamos cerca de 20 transmissões (até o momento), acumulando aproximadamente 70 horas de live, uma média de 10 horas por dia dedicadas a este projeto.
Por ser um framework e uma linguagem novos para mim, é evidente que ainda não tenho total domínio sobre o Ruby on Rails. No entanto, com toda essa dedicação ao desafio, pude aplicar não só conhecimentos externos, mas também boas práticas de desenvolvimento.
Se quiser acompanhar o processo, você pode acessar a playlist das lives deste projeto no meu canal do YouTube:
Playlist das Lives: Lives
Canal no YouTube: Canal
- 📚 Antes de qualquer coisa, leia...
- 💪 Desafio Proposto
- ⚙️ Tecnologias Utilizadas
- 🛠️ Ferramentas Utilizadas
- 🔧 Principais Gems Utilizadas
- 📚 Materiais de Apoio Utilizados para o Desenvolvimento
- 💼 Serviços
- 🔒 Permissões
- 🗃️ Banco de Dados
- 🚀 Executando o Projeto
- 🧪 Testes
- 📝 Documentação da API
- 🙌 Contribuições
- 🖼️ Imagens da Web do Projeto
- 💻 Ainda sobre o Desenvolvimento
- 📄 Licença
O sistema tem como objetivo armazenar os registros de entradas de pessoas (visitantes) que frequentam uma determinada unidade de uma instituição.
- Cadastro de visitantes: Solicita informações como CPF, nome, RG, telefone e foto (webcam).
- Consulta de visitantes: Se o visitante já estiver cadastrado, ao preencher o CPF, o sistema preenche os dados automaticamente.
- Registro de visita: Solicita o setor e o funcionário (opcional) ao qual a visita será realizada, e registra a data e hora da entrada.
- A instituição possui várias unidades, sendo que cada unidade armazena apenas os dados das visitas realizadas nela, mas compartilha o cadastro dos visitantes para agilizar o processo.
- Setores e Funcionários: Cada unidade possui vários setores e funcionários, que devem ser informados no momento do registro de uma visita.
- Administrador: Pode cadastrar unidades, setores, funcionários e usuários.
- Atendente: Responsável pelo cadastro de visitantes e registro de visitas apenas na sua unidade.
- Funcionário: Pode visualizar a lista de visitantes aguardando e notificar o sistema sobre a realização da visita.
- O sistema exibe as funcionalidades conforme a permissão de cada usuário.
- Sistema Web
- Arquitetura MVC com Ruby on Rails
- Ruby como linguagem de programação
- Devise para autenticação de usuários
- Cancancan para controle de permissões de usuários
O projeto é desenvolvido utilizando Ruby on Rails, uma framework web popular para construção de aplicações web de forma rápida e eficiente.
Este projeto utiliza o Tailwind CSS para a estilização. O Tailwind é um framework CSS utilitário que permite criar designs modernos e responsivos de maneira prática e ágil.
O Tailwind CSS está configurado no arquivo Procfile.dev para ser observado e recompilado automaticamente durante o desenvolvimento. A configuração é a seguinte:
web: bin/rails server
css: bin/rails tailwindcss:watch
Os estilos globais do Tailwind CSS são importados no arquivo application.css:
@import "tailwindcss";
Para mais informações sobre como utilizar o Tailwind CSS, consulte a documentação oficial.
Por padrão, o Rubocop já vem configurado em projetos Rails, mas com configurações básicas. Para melhorar a qualidade do código, utilizei um repositório com configurações avançadas de linter recomendadas para projetos Rails.
Repositório: Standard Ruby
Se quiser as configurações avançadas, basta copiar o arquivo base.yml e colocá-lo no seu .rubocop.yml na raiz do projeto.
- Docker foi utilizado para criar contêineres no ambiente de desenvolvimento, garantindo um processo de configuração e execução mais eficiente.
- Portainer foi adotado como interface web para gerenciar os contêineres Docker de maneira visual e intuitiva.
- Git foi utilizado para o controle de versão do projeto.
- GitHub foi a plataforma escolhida para hospedar o repositório e possibilitar a colaboração.
- DBeaver foi utilizado para o gerenciamento e manipulação do banco de dados, oferecendo uma interface gráfica que facilita o gerenciamento das tabelas e dados.
- Visual Studio Code (VSCode) foi a principal IDE utilizada no desenvolvimento do código, com suporte a diversas extensões que aumentam a produtividade e eficiência.
- O terminal Linux foi amplamente utilizado para realizar operações no sistema, além de interagir diretamente com o projeto.
- Utilizei o dbdiagram.io para modelar o banco de dados, criando diagramas relacionais que ajudam a visualizar a estrutura e as interações entre as tabelas.
- A Inteligência Artificial foi utilizada para esclarecer dúvidas, analisar erros, buscar exemplos e outras finalidades de suporte. NUNCA foi utilizada para escrever código diretamente no projeto.
- O Notion foi utilizado para anotações, definição de metas, organização de ideias e planejamento geral do projeto.
- Utilizei o Draw.io para compreender melhor o projeto e criar modelos, como fluxos de dados e diagramas de arquitetura.
- rails (~> 8.0.1): Framework principal para o desenvolvimento de aplicações web.
- pg (~> 1.5, >= 1.5.6): Gem para integração com o banco de dados PostgreSQL.
- dotenv-rails (~> 2.1, >= 2.1.1): Carrega variáveis de ambiente a partir de um arquivo .env.
- devise: Gem para autenticação de usuários.
- cancancan: Gem para controle de permissões e autorização de usuários.
- carrierwave (~> 2.0): Responsável pelo upload de arquivos.
- mini_magick: Utilizada para o processamento de imagens.
- fog-aws: Gem para armazenamento de arquivos na AWS S3.
- brazilian_documents (~> 0.1.4): Valida documentos brasileiros, como CPF e RG.
- phonelib: Realiza a validação de números de telefone.
- puma (>= 5.0): Servidor web utilizado para rodar a aplicação.
Um canal que me ajudou bastante durante o processo foi o RailsGO. Recomendo a todos que estão aprendendo Ruby on Rails!
RailsGO no YouTube
- Cancancan - Gem para controle de permissões e autorização de usuários.
- Carrierwave - Gem para upload de arquivos.
- Phonelib - Gem para validação de números de telefone.
- Devise - Gem para autenticação de usuários.
- dotenv - Gem para carregar variáveis de ambiente.
- Tailwind UI - Recursos e componentes prontos para o Tailwind CSS.
- Brazilian Documents - Validação de documentos brasileiros.
- Getting Started with Rails - Guia oficial para começar com Rails.
- Ruby Documentation - Documentação oficial da linguagem Ruby.
- Webcam API - MDN - Documentação sobre o uso da webcam no navegador.
- Standard Ruby - Repositório com configurações de linter para Ruby.
O projeto utiliza o Action Mailer para enviar e-mails pelos serviços da gem Devise. Para isso, escolhi o serviço do Gmail. A configuração do serviço de e-mail está no arquivo development.rb
:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
domain: "gmail.com",
user_name: ENV["EMAIL_GMAIL"],
password: ENV["PASSWORD_GMAIL"],
authentication: "plain",
enable_starttls_auto: true
}
Aqui, as credenciais de e-mail são carregadas a partir das variáveis de ambiente, garantindo a segurança das informações sensíveis.
O projeto utiliza o AWS S3 para armazenamento de fotos dos visitantes e usuários. A configuração do serviço está no arquivo carrierwave.rb
, que utiliza a gem CarrierWave para integrar o armazenamento no S3:
CarrierWave.configure do |config|
config.fog_credentials = {
provider: "AWS",
aws_access_key_id: ENV["AWS_ACCESS_KEY_ID"],
aws_secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
region: ENV["AWS_REGION"],
endpoint: "https://s3.sa-east-1.amazonaws.com"
}
config.fog_directory = ENV["AWS_BUCKET_NAME"]
config.fog_public = false
config.fog_attributes = {"Cache-Control" => "max-age=315576000"}
end
As credenciais de acesso à AWS também são carregadas a partir das variáveis de ambiente para garantir a segurança das informações sensíveis.
O projeto está configurado para ser executado em containers Docker. Abaixo está a configuração necessária para rodar a aplicação em um ambiente isolado.
O arquivo Dockerfile contém a configuração para a criação da imagem Docker:
FROM ruby:3.2.0
RUN apt-get update -qq && apt-get install -y \
build-essential \
libpq-dev \
nodejs \
postgresql-client
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
EXPOSE 3000
CMD ["bash", "-c", "rm -f tmp/pids/server.pid && bundle exec rails server -b '0.0.0.0'"]
O arquivo docker-compose.yml é utilizado para organizar os containers, definindo as configurações de rede e volumes:
version: '3'
services:
db:
image: postgres
restart: always
ports:
- "5432:5432"
volumes:
- ./pgdata:/data/postgres
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
networks:
- app-network
web:
build:
context: .
dockerfile: Dockerfile
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails server -b '0.0.0.0'"
volumes:
- ".:/app"
ports:
- "3000:3000"
depends_on:
- db
networks:
- app-network
volumes:
pgdata:
driver: local
networks:
app-network:
- Dockerfile: Define a construção da imagem Docker, incluindo dependências necessárias e a execução do servidor Rails.
- docker-compose.yml: Configura os containers para o banco de dados (PostgreSQL) e o servidor web (Rails), garantindo que ambos compartilhem a mesma rede e volumes persistentes.
As permissões no sistema são baseadas em roles (funções) dos usuários, e os valores para cada role são os seguintes:
- 0 = employee (funcionário)
- 1 = attendant (atendente)
- 2 = admin (admin)
A gem CanCanCan é usada para configurar as permissões dos usuários. Você pode encontrar o arquivo de permissões completo em app/models/ability.rb
.
def initialize(user)
case user.role
when "admin"
can :manage, :all
when "attendant"
can :read, Visit, unit_id: user.unit_id
can :read, Visitor
can :update, Visit, unit_id: user.unit_id
can :update, Visitor
can :create, Visit
can :create, Visitor
can :verify_by_cpf, Visitor
when "employee"
can :read, Visit, unit_id: user.unit_id
can :update, Visit, unit_id: user.unit_id
end
end
- Admin tem permissões completas e pode gerenciar todos os recursos do sistema.
- Attendant pode ler, criar e atualizar registros de visitas e visitantes dentro da sua unidade específica, além de realizar a verificação por CPF de visitantes.
- Employee pode ler e atualizar visitas dentro da sua unidade.
O banco de dados foi projetado e estruturado de acordo com as três primeiras formas normais (1FN, 2FN e 3FN), garantindo um alto nível de integridade e eficiência na organização dos dados.
-
Primeira Forma Normal (1FN): Todas as colunas nas tabelas contêm valores atômicos, sem campos que armazenem múltiplos valores ou listas. Cada valor é único e independente dentro de suas respectivas colunas.
-
Segunda Forma Normal (2FN): Todas as colunas não-chave dependem completamente da chave primária, eliminando dependências parciais.
-
Terceira Forma Normal (3FN): Não há dependências transitivas entre as colunas, ou seja, as colunas dependem apenas da chave primária e não umas das outras.
- 1..n: Um para muitos
- 1..1: Um para um
- n..1: Muitos para um
- n..n: Muitos para muitos
-
Tabela
sectors
(Setores):belongs_to :unit
: Cada setor pertence a uma unidade.has_many :visits
: Um setor pode ter várias visitas registradas.
-
Tabela
units
(Unidades):has_many :sectors
: Uma unidade pode ter vários setores.has_many :users
: Uma unidade pode ter vários usuários.has_many :visits
: Uma unidade pode ter várias visitas.
-
Tabela
users
(Usuários):belongs_to :unit, optional: true
: Um usuário pertence a uma unidade (opcional).belongs_to :sector, optional: true
: Um usuário pertence a um setor (opcional).has_many :visits
: Um usuário pode ter várias visitas.
-
Tabela
visitors
(Visitantes):has_many :visits
: Um visitante pode ter várias visitas.
-
Tabela
visits
(Visitas):belongs_to :visitor
: Cada visita pertence a um visitante.belongs_to :unit
: Cada visita pertence a uma unidade.belongs_to :sector
: Cada visita pertence a um setor.belongs_to :user, optional: true
: Cada visita pode ser associada a um usuário, mas isso é opcional.
sectors
: Tem uma chave estrangeira (unit_id
) que se relaciona com a tabelaunits
.users
: Tem chaves estrangeiras (unit_id
,sector_id
) que se relacionam comunits
esectors
.visits
: Tem chaves estrangeiras (visitor_id
,unit_id
,sector_id
,user_id
) que se relacionam comvisitors
,units
,sectors
eusers
.
-
Campo
status
da tabelavisits
: Define o status da visita com os seguintes valores:pending
(pendente)completed
(completada)absent
(ausente)
-
Campo
role
da tabelausers
: Define o papel do usuário com os seguintes valores:employee
(funcionário)attendant
(atendente)admin
(administrador)
- Validações em várias tabelas garantem que os dados inseridos sejam válidos, como CPF, RG, e-mail, entre outros.
User
eVisitor
possuem validações específicas para Telefone, CPF e RG, garantindo que sigam os padrões brasileiros.
-
Clone o repositório do projeto:
Se você ainda não tem o projeto em sua máquina local, clone o repositório utilizando o comando:
git clone <URL_DO_REPOSITORIO>
-
Navegue até a pasta do projeto:
Entre na pasta do projeto com o comando:
cd nome-do-projeto
-
Crie o arquivo
.env
:Na raiz do projeto, crie um arquivo
.env
com as variáveis de ambiente necessárias. Para isso, adicione os seguintes parâmetros (sem valores) conforme descrito:POSTGRES_USER=seu_usuario_no_banco POSTGRES_PASSWORD=sua_senha_do_banco POSTGRES_DB=nome_do_banco DATABASE_HOST=localhost EMAIL_GMAIL=seu_email@gmail.com PASSWORD_GMAIL=sua_senha_de_aplicativo AWS_ACCESS_KEY_ID=sua_chave_de_acesso_aws AWS_SECRET_ACCESS_KEY=sua_chave_secreta_aws AWS_BUCKET_NAME=seu_nome_do_bucket_aws AWS_REGION=regiao_do_bucket_aws
- POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB: Credenciais e informações de configuração para o banco de dados PostgreSQL.
- DATABASE_HOST: O endereço onde o banco de dados está hospedado (geralmente
localhost
durante o desenvolvimento local). - EMAIL_GMAIL e PASSWORD_GMAIL: Credenciais de acesso ao serviço de e-mail via Gmail para enviar e-mails através do Action Mailer.
- AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_BUCKET_NAME, AWS_REGION: Credenciais e informações relacionadas ao uso do AWS S3 para o armazenamento de arquivos.
-
Instale as dependências com o
bundle
:Para instalar as dependências do projeto, execute o seguinte comando:
bundle install
Isso irá baixar e instalar todas as gems necessárias para o projeto.
-
Crie o banco de dados:
Execute o seguinte comando para criar o banco de dados:
bin/rails db:create
-
Execute as migrações:
Depois de criar o banco de dados, execute as migrações para criar as tabelas necessárias:
bin/rails db:migrate
-
Popule o banco com dados iniciais (seeds):
Se você desejar adicionar dados iniciais ao banco (como um usuário administrador), execute o comando:
bin/rails db:seed
Nota: O comando
seed
acima irá gerar um usuário admin com as seguintes informações, mas antes de executá-lo, vá até o model deuser
e desative a validação de foto. Execute o comando e depois reative a validação de foto, pois há um bug que impede a execução correta sem essa alteração, uma possível solução seria utilizar outra gem para o upload de fotos, mas, por enquanto, mantive a atual para atender aos requisitos do projeto.O arquivo está em:
app/models/user.rb
Altere a validação de foto temporariamente:
validates :photo, presence: false # Desative a validação temporariamente
Após rodar o
db:seed
, reative a validação:validates :photo, presence: true
Dados do Usuário Admin para o
seed
:email: "keyllianazevedo2@gmail.com" password: "123456", password_confirmation: "123456", confirmed_at: Time.now, role: 2, cpf: "24327784052", # CPF gerado pelo site https://www.4devs.com.br/gerador_de_cpf rg: "123456789", name: "Keyllian Azevedo", telephone: "55 92 36170584", # Telefone gerado pelo site https://geradornv.com.br/gerador-telefone/
-
Suba os containers com Docker Compose:
Caso você queira rodar o projeto em containers Docker, execute:
docker-compose up
Isso irá levantar os containers para o banco de dados e a aplicação, conforme descrito no
docker-compose.yml
.
- Acesse a aplicação:
Se tudo ocorrer sem erros, a aplicação estará disponível em http://localhost:3000
. Caso ocorra algum erro durante a execução, consulte os logs ou entre em contato para que eu possa te ajudar a resolver.
-
Parar o Docker Compose:
Se você estiver usando Docker, para parar os containers, execute:
docker-compose down
-
Rodar o servidor sem Docker:
Caso você não esteja utilizando Docker, pode rodar o servidor localmente com o comando:
bin/rails server
Por conta do limitado tempo de desenvolvimento, não consegui criar testes unitários, mas caso você queira criar testes e executá-los, o comando é o seguinte:
bin/rails test
Este comando executará os testes do projeto (caso existam) e mostrará os resultados no terminal.
Se você for adicionar ou criar novos testes, pode usar as funcionalidades da framework de testes do Rails, como Test::Unit ou RSpec, dependendo de como preferir estruturar seus testes.
Aqui está a seção completa de Documentação da API para o seu guia de execução do projeto:
Neste período, o tempo foi corrido e, por isso, não consegui implementar o Swagger para a documentação das rotas. No entanto, aqui estão as principais rotas da API gerado por IA:
-
POST /users/sign_in
- Descrição: Realiza o login do usuário.
- Parâmetros:
email
: string (obrigatório)password
: string (obrigatório)
- Respostas:
200 OK
: Login bem-sucedido.401 Unauthorized
: Credenciais inválidas.
-
DELETE /users/sign_out
- Descrição: Realiza o logout do usuário.
- Respostas:
204 No Content
: Logout bem-sucedido.
-
POST /users
- Descrição: Cria um novo usuário.
- Parâmetros:
email
: string (obrigatório)password
: string (obrigatório)name
: string (obrigatório)cpf
: string (obrigatório)rg
: string (obrigatório)telephone
: string (obrigatório)photo
: arquivo (obrigatório)role
: integer (obrigatório)unit_id
: uuid (opcional)sector_id
: uuid (opcional)
- Respostas:
201 Created
: Usuário criado com sucesso.422 Unprocessable Entity
: Erro de validação.
-
GET /users
- Descrição: Retorna a lista de usuários.
- Respostas:
200 OK
: Lista de usuários.
-
GET /visitors
- Descrição: Retorna a lista de visitantes.
- Respostas:
200 OK
: Lista de visitantes.
-
POST /visitors
- Descrição: Cria um novo visitante.
- Parâmetros:
name
: string (obrigatório)cpf
: string (obrigatório)rg
: string (obrigatório)telephone
: string (obrigatório)photo
: arquivo (obrigatório)
- Respostas:
201 Created
: Visitante criado com sucesso.422 Unprocessable Entity
: Erro de validação.
-
GET /visitors/:id
- Descrição: Retorna os detalhes de um visitante específico.
- Parâmetros:
id
: uuid (obrigatório)
- Respostas:
200 OK
: Detalhes do visitante.404 Not Found
: Visitante não encontrado.
-
GET /visits
- Descrição: Retorna a lista de visitas.
- Respostas:
200 OK
: Lista de visitas.
-
POST /visits
- Descrição: Cria uma nova visita.
- Parâmetros:
visitor_id
: uuid (obrigatório)unit_id
: uuid (obrigatório)sector_id
: uuid (obrigatório)user_id
: uuid (opcional)date_time
: datetime (obrigatório)status
: integer (obrigatório)
- Respostas:
201 Created
: Visita criada com sucesso.422 Unprocessable Entity
: Erro de validação.
-
GET /visits/:id
- Descrição: Retorna os detalhes de uma visita específica.
- Parâmetros:
id
: uuid (obrigatório)
- Respostas:
200 OK
: Detalhes da visita.404 Not Found
: Visita não encontrada.
-
GET /sectors
- Descrição: Retorna a lista de setores.
- Respostas:
200 OK
: Lista de setores.
-
POST /sectors
- Descrição: Cria um novo setor.
- Parâmetros:
name
: string (obrigatório)unit_id
: uuid (obrigatório)
- Respostas:
201 Created
: Setor criado com sucesso.422 Unprocessable Entity
: Erro de validação.
-
GET /sectors/:id
- Descrição: Retorna os detalhes de um setor específico.
- Parâmetros:
id
: uuid (obrigatório)
- Respostas:
200 OK
: Detalhes do setor.404 Not Found
: Setor não encontrado.
-
GET /units
- Descrição: Retorna a lista de unidades.
- Respostas:
200 OK
: Lista de unidades.
-
POST /units
- Descrição: Cria uma nova unidade.
- Parâmetros:
name
: string (obrigatório)email
: string (opcional)
- Respostas:
201 Created
: Unidade criada com sucesso.422 Unprocessable Entity
: Erro de validação.
-
GET /units/:id
- Descrição: Retorna os detalhes de uma unidade específica.
- Parâmetros:
id
: uuid (obrigatório)
- Respostas:
200 OK
: Detalhes da unidade.404 Not Found
: Unidade não encontrada.
Caso queira documentar mais rotas ou utilizar ferramentas como o Swagger no futuro, você pode facilmente adicionar essas rotas a partir dessa estrutura inicial.
Contribuições para este projeto são bem-vindas! Se você deseja melhorar ou adicionar algo ao projeto, fique à vontade para:
-
Abrir Issues: Caso encontre algum bug, tenha sugestões de melhorias ou queira discutir novas funcionalidades, abra uma issue para que possamos analisar e discutir a melhor forma de implementar.
-
Criar Pull Requests (PRs): Se você desenvolveu alguma funcionalidade, corrigiu um bug ou fez melhorias, envie um pull request para a branch principal. As contribuições serão avaliadas e, se estiverem de acordo com os padrões do projeto, serão aceitas.
Se este projeto tiver continuidade, podemos seguir desenvolvendo e evoluindo juntos!
Agradeço qualquer contribuição!
Antes de ver a parte web do projeto, gostaria de pedir desculpas por não ter um designer dedicado e por não ser muito experiente na parte de front-end. Contudo, tentei fazer algo simples, prático e agradável. Os modelos de views foram baseados na documentação com show, index, update, delete e new, então todos os modelos seguem a mesma estrutura, claro que com variações nas informações de cada modelo.
Abaixo estão algumas imagens do projeto. Para ver o projeto completo, acesse o link do vídeo no YouTube, onde mostro o projeto em detalhes!
Imagem | Link |
---|---|
Visualizar | |
Visualizar | |
Visualizar | |
Visualizar | |
Visualizar | |
Visualizar | |
Visualizar | |
Visualizar | |
Visualizar | |
Visualizar | |
Visualizar |
- Clique no link de "Visualizar" correspondente à imagem desejada.
- Você será redirecionado para o Google Drive, onde poderá visualizar e baixar a imagem.
Aqui estão algumas imagens das anotações que fiz durante o desenvolvimento. Não considere a bagunça hahaha!
Este projeto está licenciado sob a licença MIT. Veja o arquivo LICENSE para mais detalhes.