- 📱 Arquitetura Híbrida: API REST para integração mobile + Interface web Thymeleaf
- 🔒 Segurança Robusta: Autenticação JWT e Spring Security
- 📊 Gestão Completa: Controle de funcionários, frotas, pátios e status em tempo real
- ☁️ Deploy em Produção: Aplicação rodando no Render com PostgreSQL
| Ambiente | URL | Status |
|---|---|---|
| 🚀 Produção | mottuflowjava.onrender.com | |
| 💻 Local | http://localhost:8080 | Desenvolvimento |
⚠️ Nota: O serviço gratuito do Render entra em modo sleep após inatividade. O primeiro acesso pode levar ~50 segundos para iniciar.
O projeto utiliza branches separadas para gerenciar ambientes de desenvolvimento e produção:
| Branch | Ambiente | Banco de Dados | URL |
|---|---|---|---|
main |
Desenvolvimento Local | MySQL 8.0+ | http://localhost:8080 |
sprint4 |
Produção | PostgreSQL 15 (Render) | https://mottuflowjava.onrender.com |
| Módulo | Descrição | Funcionalidades |
|---|---|---|
| 👥 Funcionários | Gestão de Funcionários | CRUD completo, perfis de acesso, histórico |
| 🏪 Pátios | Gerenciamento de locais | Cadastro, monitoramento, capacidade |
| 🏍️ Motos | Controle de frota | Registro, status, localização, manutenção |
| 📹 Câmeras | Sistema de monitoramento | Configuração e status |
| 🏷️ ArUco Tags | Identificação visual | Cadastro e rastreamento |
| 📍 Status & Localização | Tracking em tempo real | Posição, disponibilidade, alertas |
- ✅ API REST Completa - Documentação OpenAPI/Swagger
- ✅ Interface Web Responsiva - Thymeleaf
- ✅ Autenticação Segura - JWT + Spring Security
- ✅ Migração de Dados - Flyway para versionamento de BD
- ✅ Validação de Dados - Bean Validation integrado
- ✅ Deploy em Produção - Render + Render PostgreSQL
- Java 21 - LTS com recursos modernos
- Spring Boot 3.x - Framework principal
- Spring Data JPA - Persistência de dados
- Spring Security - Autenticação e autorização
- Spring Web - API REST
- PostgreSQL 15 - Banco de dados em produção(Disponibilizado pelo Render)
- MySQL 8.0 - Suporte para desenvolvimento local
- PostgreSQL (Render) - Banco de dados gerenciado
- Flyway - Controle de versão do schema
- HikariCP - Pool de conexões otimizado
- Thymeleaf - Engine de templates
- Render - Plataforma de deploy em nuvem
MottuFlow/
├── 📄 DockerFile # Arquivo DockerFile para Deploy(apenas disponível na branch `sprint4`)
├── 📁 src/main/java/com/sprint/MottuFlow/
│ ├── 📁 controller/ # Controladores REST e Web
│ │ ├── 📁 rest/ # Endpoints API REST
│ │ └── 📁 web/ # Controladores Thymeleaf
│ ├── 📁 domain/ # Entidades de domínio (com Model, Repository, Service e DTO)
│ │ ├── 📁 arucotag/ # ArUco Tags
│ │ ├── 📁 autenticao/ # Autenticação
│ │ ├── 📁 camera/ # Câmeras
│ │ ├── 📁 funcionario/ # Funcionários
│ │ ├── 📁 localidade/ # Localidades
│ │ ├── 📁 moto/ # Motocicletas
│ │ ├── 📁 patio/ # Pátios
│ │ └── 📁 status/ # Status das motos
│ ├── 📁 infra/ # Infraestrutura
│ │ ├── 📁 exception/ # Tratamento de exceções
│ │ └── 📁 security/ # Configurações de segurança
│ └── 📄 MottuFlowApplication.java
├── 📁 src/main/resources/
│ ├── 📁 db/migration/ # Scripts Flyway
│ ├── 📁 static/ # Recursos estáticos
│ │ ├── 📁 css/ # Arquivos CSS
│ │ └── 📁 images/ # Imagens
│ ├── 📁 templates/ # Templates Thymeleaf
│ │ ├── 📁 arucotags/ # Templates ArUco Tags
│ │ ├── 📁 cameras/ # Templates Câmeras
│ │ ├── 📁 components/ # Componentes reutilizáveis
│ │ ├── 📁 funcionarios/ # Templates Funcionários
│ │ ├── 📁 localidades/ # Templates Localidades
│ │ ├── 📁 motos/ # Templates Motocicletas
│ │ ├── 📁 patios/ # Templates Pátios
│ │ └── 📁 status/ # Templates Status
│ └── 📄 application.properties # Configuração (varia por branch)
└── 📄 pom.xml # Dependências Maven
- Java 21+ (OpenJDK ou Oracle JDK)
- PostgreSQL 15+ (produção) ou MySQL 8.0+ (desenvolvimento local)
- Maven 3.8+ (Download)
- Git (Download)
- Database Client (Extensão para consultar o banco de dados)
# Clone o repositório
git clone -b main https://github.com/thejaobiell/MottuFlowJava.git
cd MottuFlowJava
# (Opcional) Troque para a branch de deploy
git checkout sprint4
cd MottuFlow
./mvnw spring-boot:run# Clone o repositório
git clone -b main https://github.com/thejaobiell/MottuFlowJava.git
cd MottuFlowJava
# (Opcional) Troque para a branch de deploy
git checkout sprint4
cd MottuFlow
# Execute a aplicação
.\mvnw.cmd spring-boot:runA aplicação utiliza configurações diferentes dependendo da branch:
sudo apt update
sudo apt install mysql-server mysql-client
sudo mysql_secure_installation- Baixe o MySQL Installer: Download MySQL Installer
- Durante a instalação, escolha:
- Server Only (somente servidor) ou Full (se quiser Workbench e utilitários).
- Configure a senha do usuário
root.
- Após a instalação, inicie o MySQL.
- Para acessar via terminal do Windows:
- Pressione
Win + R, digitecmde execute:
mysql -u root -p
- Digite a senha configurada.
- Pressione
-- Execute no MySQL como root
CREATE USER 'mottu_user'@'%' IDENTIFIED BY 'user123';
GRANT ALL PRIVILEGES ON mottuflow.* TO 'mottu_user'@'%';
FLUSH PRIVILEGES;spring.application.name=MottuFlow
spring.datasource.url=jdbc:mysql://localhost:3306/mottuflow?createDatabaseIfNotExist=true
spring.datasource.username=mottu_user
spring.datasource.password=user123
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.keepalive-time=300000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.connection-test-query=SELECT 1
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.flyway.repair=true
spring.flyway.repair-on-migrate=true
logging.level.root=WARN
logging.level.org.springframework=WARN
logging.level.org.hibernate=WARN
logging.level.com.sprint.MottuFlow=WARN
spring.main.allow-bean-definition-overriding=true
server.address=0.0.0.0
server.port=8080O PostgreSQL é usado automaticamente na branch sprint4 para produção no Render.
HOST: dpg-d3sh9eili9vc73fr27ug-a.oregon-postgres.render.com
USERNAME: rm554874
PASSWORD: F11qMduTmfLy8Xw15NBCTbsr7ypmBPbi
DATABASE: mottuflowdb
PORT: 5432spring.application.name=MottuFlow
spring.datasource.url=${DATABASE_URL}
spring.datasource.username=${DATABASE_USERNAME}
spring.datasource.password=${DATABASE_PASSWORD}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.keepalive-time=300000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.connection-test-query=SELECT 1
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false
spring.jpa.open-in-view=false
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.flyway.repair=true
spring.flyway.repair-on-migrate=true
logging.level.root=WARN
spring.main.allow-bean-definition-overriding=true
server.address=0.0.0.0
server.port=${PORT:8080}- Abra o VSCode
- Acesse a aba de Extensões (Ctrl+Shift+X)
- Instale as seguintes extensões:
- Database Client (cweijan.vscode-database-client2)
- Database Client JDBC (cweijan.dbclient-jdbc)
- Clique no ícone do Database Client na barra lateral do VSCode
- Clique em "Create Connection" (ícone de +)
- Selecione MySQL
- Preencha os dados:
Host: localhost Port: 3306 Username: mottu_user Password: user123 Database: mottuflow - Clique em Connect
- Clique no ícone do Database Client na barra lateral do VSCode
- Clique em "Create Connection" (ícone de +)
- Selecione PostgreSQL
- Preencha os dados:
Host: dpg-d3sh9eili9vc73fr27ug-a.oregon-postgres.render.com Port: 5432 Username: rm554874 Password: F11qMduTmfLy8Xw15NBCTbsr7ypmBPbi Database: mottuflowdb - Marque a opção SSL (obrigatório para Render)
- Clique em Connect
- Expanda a conexão criada
- Navegue por Schemas → Public → Tables
- Clique com botão direito em uma tabela para:
- Show Table Data: Visualizar dados
- Show Create Statement: Ver o SQL de criação
A aplicação está disponível em: mottuflowjava.onrender.com
⚠️ Importante: No plano gratuito do Render, a aplicação entra em modo sleep após 15 minutos de inatividade. O primeiro acesso pode levar até 50 segundos para "acordar" o serviço.
O Render verifica automaticamente a saúde da aplicação em: /actuator/health
./mvnw spring-boot:runSaída esperada:
██████╗ ███╗ ██╗██╗ ██╗███╗ ██╗███████╗██╗
██╔═══██╗████╗ ██║██║ ██║████╗ ██║██╔════╝██║
██║ ██║██╔██╗ ██║██║ ██║██╔██╗ ██║█████╗ ██║
██║ ██║██║╚██╗██║██║ ██║██║╚██╗██║██╔══╝ ╚═╝
╚██████╔╝██║ ╚████║███████╗██║██║ ╚████║███████╗██╗
╚═════╝ ╚═╝ ╚═══╝╚══════╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝
Clique aqui para acessar o Thymeleaf: http://localhost:8080
Clique aqui para acessar o Swagger UI: http://localhost:8080/swagger-ui/index.html
| Serviço | URL Local | URL Produção | Descrição |
|---|---|---|---|
| 🖥️ Interface Web | http://localhost:8080 | https://mottuflowjava.onrender.com | Dashboard principal |
| 📡 API REST | http://localhost:8080/api | https://mottuflowjava.onrender.com/api | Endpoints REST |
| 📚 Documentação | http://localhost:8080/swagger-ui.html | https://mottuflowjava.onrender.com/swagger-ui.html | Swagger UI |
| Usuário | Senha | Cargo | Acesso |
|---|---|---|---|
admin@email.com |
adminmottu |
Administrador | Completo |
joao@email.com |
joao123 |
Mecânico | Limitado |
maria@email.com |
maria123 |
Gerente | Completo |
Recomendado usar a conta de Administrador para teste
O Flyway gerencia as migrações automaticamente:
src/main/resources/db/
└── migration/
├── V1__create-table-funcionario.sql
└── V2__create-table-patio.sql
Todas as requisições para a API MottuFlow exigem autenticação via JWT (JSON Web Token).
-
Importe a coleção API - MottuFlow.postman_collection.json no Postman.
-
Configure a variável de ambiente
baseURL:- Local:
http://localhost:8080/api - Produção:
https://mottuflowjava.onrender.com/api
- Local:
-
No menu
0 - JWT, execute o POST Pegar Token JWT, informando no body oemailesenhado funcionário:{ "email": "admin@email.com", "senha": "adminmottu" } -
Copie o valor de
tokenAcessoretornado. -
Vá até API - MottuFlow → Variables.
-
Substitua o valor da variável
jwtpelo seu token de acesso. -
Agora todos os endpoints da coleção já estarão autenticados!
- Autenticação: Bearer Token (JWT)
- Content-Type:
application/json
{{baseUrl}}:- Local:
http://localhost:8080/api - Produção:
https://mottuflowjava.onrender.com/api
- Local:
{{jwt}}: Token JWT obtido no login
POST /login
Content-Type: application/json
{
"email": "admin@email.com",
"senha": "adminmottu"
}POST /atualizar-token
Content-Type: application/json
{
"refreshToken": "seu_refresh_token_aqui"
}POST /verificar-jwt
Content-Type: application/json
{
"tokenAcesso": "seu_token_jwt_aqui"
}GET /funcionario/listar
Authorization: Bearer {jwt_token}GET /funcionario/buscar-por-id/{id}
Authorization: Bearer {jwt_token}GET /funcionario/buscar-por-cpf/{cpf}
Authorization: Bearer {jwt_token}Exemplo: /funcionario/buscar-por-cpf/000.000.000-00
POST /funcionario/cadastrar
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"nome": "Novo Funcionário",
"cpf": "333.333.333-33",
"cargo": "MECANICO",
"telefone": "(33) 33333-3333",
"email": "novo@email.com",
"senha": "senha123"
}PUT /funcionario/editar/{id}
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"id": 2,
"nome": "João Mecânico Atualizado",
"cpf": "111.111.111-11",
"cargo": "MECANICO",
"telefone": "(11) 11111-1111",
"email": "joao@email.com",
"senha": "novaSenha123"
}PATCH /funcionario/alterar-senha
Content-Type: application/json
{
"email": "admin@email.com",
"senhaAtual": "adminmottu",
"novaSenha": "mottuadmin"
}DELETE /funcionario/deletar/{id}
Authorization: Bearer {jwt_token}GET /patios/listar
Authorization: Bearer {jwt_token}GET /patios/buscar-por-id/{id}
Authorization: Bearer {jwt_token}POST /patios/cadastrar
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"nome": "Patio AlfaBeta",
"endereco": "Rua Principal, 123",
"capacidadeMaxima": 500
}PUT /patios/editar/{id}
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"nome": "Patio Atualizado",
"endereco": "Rua Nova, 456",
"capacidadeMaxima": 100
}DELETE /patios/deletar/{id}
Authorization: Bearer {jwt_token}GET /motos/listar
Authorization: Bearer {jwt_token}GET /motos/motos-com-tags
Authorization: Bearer {jwt_token}GET /motos/buscar-por-id/{id}
Authorization: Bearer {jwt_token}GET /motos/buscar-por-placa/{placa}
Authorization: Bearer {jwt_token}GET /motos/buscar-por-fabricante?fabricante={fabricante}
Authorization: Bearer {jwt_token}Exemplo: /motos/buscar-por-fabricante?fabricante=Yamaha
GET /motos/buscar-por-patio/{idPatio}
Authorization: Bearer {jwt_token}POST /motos/cadastrar
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"placa": "ABC-1234",
"modelo": "Honda CB500",
"fabricante": "Honda",
"ano": 2021,
"idPatio": 2,
"localizacaoAtual": "Setor A"
}PUT /motos/editar/{id}
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"placa": "XYZ-5678",
"modelo": "Yamaha MT-07",
"fabricante": "Yamaha",
"ano": 2022,
"idPatio": 2,
"localizacaoAtual": "Setor B"
}DELETE /motos/deletar/{id}
Authorization: Bearer {jwt_token}GET /cameras/listar
Authorization: Bearer {jwt_token}GET /cameras/buscar-por-id/{id}
Authorization: Bearer {jwt_token}GET /cameras/buscar-por-status/{status}
Authorization: Bearer {jwt_token}Exemplo: /cameras/buscar-por-status/Operacional
POST /cameras/cadastrar
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"statusOperacional": "ONLINE",
"localizacaoFisica": "Entrada do Patio",
"idPatio": 2
}PUT /cameras/editar/{id}
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"statusOperacional": "INATIVA",
"localizacaoFisica": "Saida do Patio",
"idPatio": 3
}DELETE /cameras/deletar/{id}
Authorization: Bearer {jwt_token}GET /aruco-tags/listar
Authorization: Bearer {jwt_token}GET /aruco-tags/buscar-por-id/{id}
Authorization: Bearer {jwt_token}GET /aruco-tags/buscar-por-status/{status}
Authorization: Bearer {jwt_token}Exemplo: /aruco-tags/buscar-por-status/ativo
GET /aruco-tags/buscar-por-codigo/{codigo}
Authorization: Bearer {jwt_token}Exemplo: /aruco-tags/buscar-por-codigo/TAG004
POST /aruco-tags/cadastrar
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"codigo": "TAG12345",
"idMoto": 4,
"status": "ATIVO"
}PUT /aruco-tags/editar/{id}
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"codigo": "TAG99999",
"idMoto": 5,
"status": "INATIVO"
}DELETE /aruco-tags/deletar/{id}
Authorization: Bearer {jwt_token}GET /status/listar
Authorization: Bearer {jwt_token}GET /status/buscar-por-id/{id}
Authorization: Bearer {jwt_token}GET /status/buscar-por-tipo?tipoStatus={tipo}
Authorization: Bearer {jwt_token}Exemplo: /status/buscar-por-tipo?tipoStatus=BAIXA_BOLETIM_OCORRENCIA
GET /status/buscar-por-descricao?descricao={descricao}
Authorization: Bearer {jwt_token}Exemplo: /status/buscar-por-descricao?descricao=Perda por BO
GET /status/buscar-por-periodo?inicio={dataInicio}&fim={dataFim}
Authorization: Bearer {jwt_token}Exemplo: /status/buscar-por-periodo?inicio=2025-09-28T00:00:00&fim=2025-09-28T23:59:59
POST /status/cadastrar
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"idMoto": 4,
"tipoStatus": "DISPONIVEL",
"descricao": "Moto disponível para uso",
"idFuncionario": 3
}PUT /status/editar/{id}
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"idMoto": 4,
"tipoStatus": "EM_MANUTENCAO",
"descricao": "Moto em manutenção preventiva",
"idFuncionario": 2
}DELETE /status/deletar/{id}
Authorization: Bearer {jwt_token}GET /localidades/listar
Authorization: Bearer {jwt_token}GET /localidades/buscar-por-id/{id}
Authorization: Bearer {jwt_token}GET /localidades/buscar-por-patio/{idPatio}
Authorization: Bearer {jwt_token}GET /localidades/buscar-por-ponto-referencia/{pontoReferencia}
Authorization: Bearer {jwt_token}Exemplo: /localidades/buscar-por-ponto-referencia/Vaga
GET /localidades/buscar-por-periodo?dataInicio={dataInicio}&dataFim={dataFim}
Authorization: Bearer {jwt_token}Exemplo: /localidades/buscar-por-periodo?dataInicio=2025-09-06T08:00:00&dataFim=2025-09-08T08:20:00
POST /localidades/cadastrar
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"idMoto": 1,
"idPatio": 2,
"pontoReferencia": "Vaga A15",
"observacoes": "Próximo à entrada"
}PUT /localidades/editar/{id}
Authorization: Bearer {jwt_token}
Content-Type: application/json
{
"idMoto": 1,
"idPatio": 2,
"pontoReferencia": "Vaga B20",
"observacoes": "Realocada para manutenção"
}DELETE /localidades/deletar/{id}
Authorization: Bearer {jwt_token}| Código | Descrição |
|---|---|
| 200 | Sucesso na operação |
| 201 | Recurso criado com sucesso |
| 400 | Dados inválidos ou malformados |
| 401 | Token JWT ausente ou inválido |
| 403 | Acesso negado (permissões insuficientes) |
| 404 | Recurso não encontrado |
| 500 | Erro interno do servidor |
Primeiro acesso muito lento
Causa: No plano gratuito do Render, serviços ficam em sleep após 15 minutos de inatividade.
Solução: Aguarde até 50 segundos no primeiro acesso. Requisições subsequentes serão rápidas.
Erro de conexão com banco de dados local
Solução:
- Verifique se está na branch
main - Confirme se o MySQL está rodando:
sudo systemctl status mysql - Confirme as credenciais em
application.properties - Crie o banco manualmente se necessário:
CREATE DATABASE mottuflow;
Token JWT inválido ou expirado
Solução:
- Faça login novamente para obter um novo token
- Verifique se o token está sendo enviado corretamente no header
Authorization: Bearer {token} - Certifique-se de que não há espaços extras ou aspas no token. Copie apenas o código.
![]() João Gabriel Boaventura RM554874 • 2TDSB2025 |
![]() Léo Mota Lima RM557851 • 2TDSB2025 |
![]() Lucas Leal das Chagas RM551124 • 2TDSB2025 |



