Aplicação web (Thymeleaf) para gestão de locações de motos.
CRUD completo em Moto com PostgreSQL na Azure e deploy PaaS no Azure App Service via Azure CLI.
- Cadastro e manutenção de Motos (inclui listar, criar, atualizar e excluir).
- Integração com PostgreSQL Flexible Server (Azure).
- Flyway aplica/valida o schema na inicialização.
- Empacotamento com Spring Boot Loader (JAR executável).
- Centraliza o cadastro e status de motos por filial.
- Acelera locação/devolução, reduz erros e retrabalho.
- Base única para relatórios e tomada de decisão.
🟢 Arquitetura em Execução (Azure – PaaS)
┌─────────────────────────────────────────────────┐
│ DOCKER HOST │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ CONTAINER │ │ CONTAINER │ │
│ │ APP │◄───│ DATABASE │ │
│ │ Spring Boot │ │ PostgreSQL │ │
│ │ :8080 │ │ :5432 │ │
│ └─────────────────┘ └─────────────────┘ │
│ ┌─────────────┐ │
│ │ DOCKER NET │ │
│ └─────────────┘ │
└─────────────────────────┬───────────────────────┘
│
▼
┌─────────────┐
│ USUÁRIO │
│ :8080 │
└─────────────┘
-
App roda em Azure App Service (Linux) com Java 17; o site público é *.azurewebsites.net.
-
O Tomcat do App Service expõe porta 80 internamente, e o acesso do usuário acontece via HTTPS (443).
-
A aplicação se conecta ao Azure PostgreSQL Flexible Server por JDBC com SSL obrigatório.
-
Flyway executa as migrações na subida do app (cria tabelas e dados iniciais).
-
O deploy do .jar foi feito com az webapp deploy (OneDeploy/Kudu).
-
O PostgreSQL tem regras de firewall para os IPs de saída do App Service e, quando necessário, o seu IP para acessar via pgAdmin/psql.
-
Java 17 + Maven 3.9+
-
Azure CLI autenticado: az login
-
Uma subscription selecionada: az account set --subscription ""
# compila e gera jar com Boot Loader
mvn -DskipTests clean package spring-boot:repackage
# (opcional) rodar local
java -jar target/mottu-track-api-0.0.1-SNAPSHOT.jar
Verifique o MANIFEST:unzip -p target/mottu-track-api-0.0.1-SNAPSHOT.jar META-INF/MANIFEST.MF | grep -E "Main-Class|Start-Class"-
Opção App Service (requisito da disciplina).
-
Defina variáveis (ajuste se quiser):
RG="rg-challenge3-devops-558438"
LOC="eastus"
PLAN="plan-challenge3-devops-558438"
APP="app-challenge3-devops-558438"
PG="pg-challenge3-devops-558438"
PG_ADMIN="pgadmin558438"
PG_PASS="OutraSenha!F0rte_992"
PG_DB="db_challenge3_devops"
Crie recursos (pule este bloco se você já criou com os mesmos nomes):az group create -n $RG -l $LOC
az appservice plan create -g $RG -n $PLAN --sku B1 --is-linux
az webapp create -g $RG -p $PLAN -n $APP --runtime "JAVA|17-java17"
az webapp config set -g $RG -n $APP --always-on true
az postgres flexible-server create \
-g $RG -n $PG -l $LOC \
--version 16 \
--tier Burstable --sku-name B1ms --storage-size 32 \
--administrator-user $PG_ADMIN --administrator-password $PG_PASS \
--yes
PG_HOST=$(az postgres flexible-server show -g $RG -n $PG --query fullyQualifiedDomainName -o tsv)
az postgres flexible-server db create -g $RG -s $PG -d $PG_DB
App Settings (necessário mesmo que os recursos já existam):Copiar código
PG_HOST=$(az postgres flexible-server show -g $RG -n $PG --query fullyQualifiedDomainName -o tsv)
SPRING_URL="jdbc:postgresql://$PG_HOST:5432/$PG_DB?sslmode=require"
az webapp config appsettings set -g $RG -n $APP --settings \
SPRING_DATASOURCE_URL="$SPRING_URL" \
SPRING_DATASOURCE_USERNAME="$PG_ADMIN" \
SPRING_DATASOURCE_PASSWORD="$PG_PASS" \
JAVA_TOOL_OPTIONS="-Dserver.port=8080" \
WEBSITES_PORT=8080Copiar código
# garante jar correto
mvn -DskipTests clean package spring-boot:repackage
JAR=$(ls -1 target/*.jar | grep -vE 'sources|javadoc' | head -n1)
# envia com OneDeploy
az webapp deploy -g $RG -n $APP --type jar --src-path "$JAR"
# reinicia e acompanha logs
az webapp restart -g $RG -n $APP
az webapp log config -g $RG -n $APP --application-logging filesystem --level information
az webapp log tail -g $RG -n $APP- Acesse: https://$APP.azurewebsites.net/
Exemplos (ajuste rota se necessário):
Copiar código
BASE="https://$APP.azurewebsites.net"
# Criar 1
curl -s -X POST "$BASE/motos" -H "Content-Type: application/json" -d '{
"placa":"ABC1D23","modelo":"Honda CG 160","ano":2022,"status":"DISPONIVEL","filialId":1
}'
# Criar 2
curl -s -X POST "$BASE/motos" -H "Content-Type: application/json" -d '{
"placa":"XYZ4E56","modelo":"Yamaha Fazer 250","ano":2023,"status":"DISPONIVEL","filialId":1
}'
# Listar
curl -s "$BASE/motos"
# Atualizar (id=1)
curl -s -X PUT "$BASE/motos/1" -H "Content-Type: application/json" -d '{
"placa":"ABC1D23","modelo":"Honda CG 160 Start","ano":2022,"status":"LOCADA","filialId":1
}'
# Buscar por id
curl -s "$BASE/motos/1"
# Deletar (id=2)
curl -s -X DELETE "$BASE/motos/2"Crie na raiz do repositório um arquivo script_bd.sql com a DDL abaixo (usada pelo Flyway):
Copiar código
CREATE TABLE IF NOT EXISTS filial (
id BIGSERIAL PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
cidade VARCHAR(60) NOT NULL,
uf CHAR(2) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
COMMENT ON TABLE filial IS 'Filiais da Mottu';
COMMENT ON COLUMN filial.uf IS 'UF da filial';
CREATE TABLE IF NOT EXISTS moto (
id BIGSERIAL PRIMARY KEY,
placa VARCHAR(10) NOT NULL UNIQUE,
modelo VARCHAR(100) NOT NULL,
ano INT NOT NULL CHECK (ano BETWEEN 1990 AND EXTRACT(YEAR FROM NOW())::INT + 1),
status VARCHAR(20) NOT NULL DEFAULT 'DISPONIVEL',
filial_id BIGINT REFERENCES filial(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
COMMENT ON TABLE moto IS 'Cadastro de motos';
COMMENT ON COLUMN moto.status IS 'DISPONIVEL | LOCADA | MANUTENCAO';
CREATE TABLE IF NOT EXISTS usuario (
id BIGSERIAL PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(120) NOT NULL UNIQUE,
senha_hash VARCHAR(255) NOT NULL,
perfil VARCHAR(30) NOT NULL DEFAULT 'USER',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS locacao (
id BIGSERIAL PRIMARY KEY,
usuario_id BIGINT NOT NULL REFERENCES usuario(id),
moto_id BIGINT NOT NULL REFERENCES moto(id),
retirada_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
devolucao_prevista TIMESTAMPTZ,
devolucao_real TIMESTAMPTZ,
valor_total NUMERIC(10,2)
);** no main manifest attribute: refaça o build com mvn ... spring-boot:repackage e redeploy.
** App travado em “Starting the site…”: confirme:
- runtime JAVA|17-java17: az webapp config show -g $RG -n $APP --query linuxFxVersion
** App Settings: WEBSITES_PORT=8080 e JAVA_TOOL_OPTIONS=-Dserver.port=8080
** SPRING_DATASOURCE_* corretos (sem null).
| Nome | RM | GitHub |
|---|---|---|
| Enzo Dias Alfaia Mendes | 558438 | @enzodam |
| Matheus Henrique Germano Reis | 555861 | @MatheusReis48 |
| Luan Dantas dos Santos | 559004 | @lds2125 |