├── .gitignore ├── uploads ├── gato.jpg ├── 1744738136169-476288.jpg └── 1744737885879-1327999.jpeg ├── src ├── config │ ├── database.js │ ├── apiKey.js │ ├── swagger.js │ └── upload.js ├── routes │ ├── reportRoutes.js │ ├── wizardRoutes.js │ └── houseRoutes.js ├── database │ └── schema.sql ├── models │ ├── houseModel.js │ └── wizardModel.js └── controllers │ ├── houseController.js │ ├── reportController.js │ └── wizardController.js ├── server.js ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env 3 | -------------------------------------------------------------------------------- /uploads/gato.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turco-vic/BackEnd-HarryPotter.SQLRelationships/HEAD/uploads/gato.jpg -------------------------------------------------------------------------------- /uploads/1744738136169-476288.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turco-vic/BackEnd-HarryPotter.SQLRelationships/HEAD/uploads/1744738136169-476288.jpg -------------------------------------------------------------------------------- /uploads/1744737885879-1327999.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turco-vic/BackEnd-HarryPotter.SQLRelationships/HEAD/uploads/1744737885879-1327999.jpeg -------------------------------------------------------------------------------- /src/config/database.js: -------------------------------------------------------------------------------- 1 | const { Pool } = require("pg"); 2 | 3 | const pool = new Pool({ 4 | user: process.env.DB_USER, 5 | host: process.env.DB_HOST, 6 | database: process.env.DB_NAME, 7 | password: process.env.DB_PASSWORD, 8 | port: process.env.DB_PORT 9 | }); 10 | 11 | module.exports = pool; 12 | -------------------------------------------------------------------------------- /src/routes/reportRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | 4 | const reportController = require("./../controllers/reportController"); 5 | 6 | //Rota para gerar CSV 7 | router.get("/report/csv", reportController.exportWizardCSV); 8 | 9 | //Rota para gerar PDF 10 | router.get("/report/pdf", reportController.exportWizardPDF); 11 | 12 | 13 | module.exports = router; -------------------------------------------------------------------------------- /src/config/apiKey.js: -------------------------------------------------------------------------------- 1 | const apiKeyMiddleware = (req, res, next) => { 2 | const clientKey = req.headers['x-api-key']; 3 | const serverKey = process.env.API_KEY; 4 | 5 | if (!clientKey) { 6 | return res.status(401).json({ error: "Chave da API não fornecida!" }) 7 | } 8 | if (clientKey !== serverKey) { 9 | return res.status(403).json({ error: "Chave da API incorreta! Sem autorização." }) 10 | } 11 | 12 | next(); // Passou pode continuar! 13 | 14 | }; 15 | 16 | module.exports = apiKeyMiddleware; -------------------------------------------------------------------------------- /src/config/swagger.js: -------------------------------------------------------------------------------- 1 | // swagger.js 2 | const swaggerJsdoc = require('swagger-jsdoc'); 3 | const swaggerUi = require('swagger-ui-express'); 4 | 5 | const options = { 6 | definition: { 7 | openapi: '3.0.0', 8 | info: { 9 | title: 'API dos Bruxos e Casas', 10 | version: '1.0.0', 11 | description: 'Documentação da API para gerenciar bruxos e casas de Hogwarts', 12 | }, 13 | }, 14 | apis: ['./src/routes/*.js'], // <- Caminho das suas rotas 15 | }; 16 | 17 | const swaggerSpec = swaggerJsdoc(options); 18 | 19 | const setupSwagger = (app) => { 20 | app.use('/doc', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); 21 | }; 22 | 23 | module.exports = setupSwagger; 24 | -------------------------------------------------------------------------------- /src/database/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE hp; 2 | 3 | \c hp; 4 | 5 | CREATE TABLE houses ( 6 | id SERIAL PRIMARY KEY, 7 | name VARCHAR(100) UNIQUE NOT NULL, 8 | founder VARCHAR(100) NOT NULL 9 | ); 10 | 11 | CREATE TABLE wizards ( 12 | id SERIAL PRIMARY KEY, 13 | name VARCHAR(100) NOT NULL, 14 | house_id INTEGER REFERENCES houses(id) ON DELETE SET NULL 15 | ); 16 | 17 | INSERT INTO houses (name, founder) VALUES 18 | ('Grifinória', 'Godric Gryffindor'), 19 | ('Sonserina', 'Salazar Slytherin'), 20 | ('Corvinal', 'Rowena Ravenclaw'), 21 | ('Lufa-Lufa', 'Helga Hufflepuff'); 22 | 23 | INSERT INTO wizards (name, house_id) VALUES 24 | ('Harry Potter', 1), 25 | ('Draco Malfoy', 2), 26 | ('Luna Lovegood', 3), 27 | ('Cedrico Diggory', 4); 28 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const express = require("express"); 3 | const cors = require("cors"); 4 | const wizardRoutes = require("./src/routes/wizardRoutes"); 5 | const houseRoutes = require("./src/routes/houseRoutes"); 6 | const reportRoutes = require ("./src/routes/reportRoutes") 7 | const setupSwagger = require('./src/config/swagger'); // Swagger aqui 8 | const path = require("path"); 9 | 10 | 11 | const app = express(); 12 | app.use(cors()); 13 | app.use(express.json()); 14 | 15 | app.use("/api/wizards", wizardRoutes); 16 | app.use("/api/houses", houseRoutes); 17 | app.use("/api", reportRoutes); 18 | setupSwagger(app); // Ativa o Swagger 19 | app.use("/uploads", express.static(path.join(__dirname, "uploads"))); 20 | 21 | const PORT = process.env.PORT || 3000; 22 | app.listen(PORT, () => { 23 | console.log(`🚀 Servidor rodando em http://localhost:${PORT}`); 24 | }); 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend-api.relationships", 3 | "version": "1.0.0", 4 | "main": "server.js", 5 | "scripts": { 6 | "start": "node server.js", 7 | "dev": "nodemon server.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/turco-vic/BackEnd-API.Relationships.git" 12 | }, 13 | "keywords": [ 14 | "SENAI, Back-End, Data Base, API" 15 | ], 16 | "author": "Enzo", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/turco-vic/BackEnd-API.Relationships/issues" 20 | }, 21 | "homepage": "https://github.com/turco-vic/BackEnd-API.Relationships#readme", 22 | "description": "", 23 | "dependencies": { 24 | "cors": "^2.8.5", 25 | "dotenv": "^16.4.7", 26 | "express": "^5.1.0", 27 | "fast-csv": "^5.0.2", 28 | "multer": "^1.4.5-lts.2", 29 | "pdfkit": "^0.16.0", 30 | "pg": "^8.14.1", 31 | "swagger-jsdoc": "^6.2.8", 32 | "swagger-ui-express": "^5.0.1" 33 | }, 34 | "devDependencies": { 35 | "nodemon": "^3.1.9" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/routes/wizardRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const wizardController = require("../controllers/wizardController"); 4 | const upload = require("../config/upload.js"); // crie a pasta middleware e o arquivo upload.js 5 | const apiKeyMiddleware = require("../config/apiKey"); 6 | 7 | router.use(apiKeyMiddleware); 8 | /** 9 | * @swagger 10 | * tags: 11 | * name: Wizards 12 | * description: Gerenciamento de bruxos 13 | */ 14 | 15 | 16 | /** 17 | * @swagger 18 | * /api/wizards: 19 | * get: 20 | * summary: Lista todos os bruxos 21 | * tags: [Wizards] 22 | * parameters: 23 | * - in: query 24 | * name: name 25 | * schema: 26 | * type: string 27 | * description: Filtro por nome 28 | * responses: 29 | * 200: 30 | * description: Lista de bruxos 31 | */ 32 | router.get("/", wizardController.getAllWizards); 33 | 34 | router.get("/:id", wizardController.getWizard); 35 | 36 | 37 | // Criar bruxo 38 | router.post("/", upload.single("photo"), wizardController.createWizard); 39 | 40 | 41 | router.put("/:id", wizardController.updateWizard); 42 | router.delete("/:id", wizardController.deleteWizard); 43 | 44 | module.exports = router; 45 | -------------------------------------------------------------------------------- /src/models/houseModel.js: -------------------------------------------------------------------------------- 1 | const pool = require("../config/database"); 2 | 3 | const getHouses = async () => { 4 | const result = await pool.query("SELECT * FROM houses"); 5 | return result.rows; 6 | }; 7 | 8 | const getHouseById = async (id) => { 9 | const result = await pool.query("SELECT * FROM houses WHERE id = $1", [id]); 10 | return result.rows[0]; 11 | }; 12 | 13 | const createHouse = async (name, founder) => { 14 | const result = await pool.query( 15 | "INSERT INTO houses (name, founder) VALUES ($1, $2) RETURNING *", 16 | [name, founder] 17 | ); 18 | return result.rows[0]; 19 | }; 20 | 21 | const updateHouse = async (id, name, founder) => { 22 | const result = await pool.query( 23 | "UPDATE houses SET name = $1, founder = $2 WHERE id = $3 RETURNING *", 24 | [name, founder, id] 25 | ); 26 | return result.rows[0]; 27 | }; 28 | 29 | const deleteHouse = async (id) => { 30 | const result = await pool.query("DELETE FROM houses WHERE id = $1 RETURNING *", [id]); 31 | if (result.rowCount === 0) { 32 | return { error: "Casa não encontrada!" }; 33 | } 34 | return { message: "Casa deletada com sucesso!" }; 35 | }; 36 | 37 | module.exports = { getHouses, getHouseById, createHouse, updateHouse, deleteHouse }; 38 | -------------------------------------------------------------------------------- /src/routes/houseRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const houseController = require("../controllers/houseController"); 4 | const apiKeyMiddleware = require("../config/apiKey"); 5 | 6 | router.use(apiKeyMiddleware); 7 | /** 8 | * @swagger 9 | * tags: 10 | * name: Houses 11 | * description: Gerenciamento de casas 12 | */ 13 | 14 | /** 15 | * @swagger 16 | * /api/houses: 17 | * get: 18 | * summary: Lista todas as casas 19 | * tags: [Houses] 20 | * responses: 21 | * 200: 22 | * description: Lista de casas. 23 | * 404: 24 | * description: Casas nao encontradas. 25 | */ 26 | router.get("/", houseController.getAllHouses); 27 | 28 | 29 | /** 30 | * @swagger 31 | * /api/houses/{id}: 32 | * get: 33 | * summary: Busca casa por ID 34 | * tags: [Houses] 35 | * parameters: 36 | * - in: path 37 | * name: id 38 | * required: true 39 | * schema: 40 | * type: integer 41 | * responses: 42 | * 200: 43 | * description: Casa encontrada 44 | * 404: 45 | * description: Casa não encontrada 46 | */ 47 | router.get("/:id", houseController.getHouse); 48 | router.post("/", houseController.createHouse); 49 | router.put("/:id", houseController.updateHouse); 50 | router.delete("/:id", houseController.deleteHouse); 51 | 52 | 53 | module.exports = router; 54 | -------------------------------------------------------------------------------- /src/models/wizardModel.js: -------------------------------------------------------------------------------- 1 | const pool = require("../config/database"); 2 | 3 | const getWizards = async () => { 4 | const result = await pool.query( 5 | `SELECT wizards.*, houses.name AS house_name 6 | FROM wizards 7 | LEFT JOIN houses ON wizards.house_id = houses.id` 8 | ); 9 | return result.rows; 10 | }; 11 | 12 | const getWizardById = async (id) => { 13 | const result = await pool.query( 14 | `SELECT wizards.*, houses.name AS house_name 15 | FROM wizards 16 | LEFT JOIN houses ON wizards.house_id = houses.id 17 | WHERE wizards.id = $1`, [id] 18 | ); 19 | return result.rows[0]; 20 | }; 21 | 22 | //Atualizar para receber photo. 23 | const createWizard = async (name, house_id, photo) => { 24 | const result = await pool.query( 25 | "INSERT INTO wizards (name, house_id, photo) VALUES ($1, $2, $3) RETURNING *", 26 | [name, house_id, photo] 27 | ); 28 | return result.rows[0]; 29 | }; 30 | 31 | const updateWizard = async (id, name, house_id) => { 32 | const result = await pool.query( 33 | "UPDATE wizards SET name = $1, house_id = $2 WHERE id = $3 RETURNING *", 34 | [name, house_id, id] 35 | ); 36 | return result.rows[0]; 37 | }; 38 | 39 | const deleteWizard = async (id) => { 40 | const result = await pool.query("DELETE FROM wizards WHERE id = $1 RETURNING *", [id]); 41 | if (result.rowCount === 0) { 42 | return { error: "Bruxo não encontrado!" }; 43 | } 44 | return { message: "Bruxo deletado com sucesso!" }; 45 | }; 46 | 47 | module.exports = { getWizards, getWizardById, createWizard, updateWizard, deleteWizard }; 48 | -------------------------------------------------------------------------------- /src/config/upload.js: -------------------------------------------------------------------------------- 1 | // Importa o módulo 'multer' para lidar com upload de arquivos 2 | const multer = require("multer"); 3 | 4 | // Importa o módulo 'path' para lidar com caminhos de arquivos 5 | const path = require("path"); 6 | 7 | // Configura onde e como os arquivos enviados serão armazenados 8 | const storage = multer.diskStorage({ 9 | // Define a pasta onde os arquivos serão salvos 10 | destination: (req, file, cb) => { 11 | cb(null, "uploads/"); // Pasta "uploads" na raiz do projeto 12 | }, 13 | // Define o nome do arquivo salvo 14 | filename: (req, file, cb) => { 15 | // Cria um nome único com a data atual + nome original do arquivo 16 | const uniqueName = Date.now() + "-" + file.originalname; 17 | cb(null, uniqueName); // Ex: 1618597654321-imagem.png 18 | }, 19 | }); 20 | 21 | // Cria o middleware do multer com configurações de armazenamento e filtro 22 | const upload = multer({ 23 | storage, // Usa a configuração de armazenamento definida acima 24 | 25 | // Filtro para aceitar apenas arquivos com extensão de imagem 26 | fileFilter: (req, file, cb) => { 27 | const ext = path.extname(file.originalname); // Pega a extensão do arquivo 28 | // Verifica se a extensão é .jpg, .jpeg ou .png 29 | if (ext !== ".jpg" && ext !== ".jpeg" && ext !== ".png") { 30 | // Rejeita o upload se não for imagem 31 | return cb(new Error("Apenas imagens são permitidas: JPG, JPEG e PNG")); 32 | } 33 | cb(null, true); // Aceita o upload 34 | } 35 | }); 36 | 37 | // Exporta o middleware 'upload' para ser usado em outras partes da aplicação 38 | module.exports = upload; 39 | -------------------------------------------------------------------------------- /src/controllers/houseController.js: -------------------------------------------------------------------------------- 1 | const houseModel = require("../models/houseModel"); 2 | 3 | const getAllHouses = async (req, res) => { 4 | try { 5 | const houses = await houseModel.getHouses(); 6 | res.json(houses); 7 | } catch (error) { 8 | res.status(500).json({ message: "Erro ao buscar Casas!" }); 9 | } 10 | }; 11 | 12 | const getHouse = async (req, res) => { 13 | try { 14 | const house = await houseModel.getHouseById(req.params.id); 15 | if (!house) { 16 | return res.status(404).json({ message: "Casa não encontrada!" }); 17 | } 18 | res.json(house); 19 | } catch (error) { 20 | res.status(500).json({ message: "Erro ao buscar Casa!" }); 21 | } 22 | }; 23 | 24 | const createHouse = async (req, res) => { 25 | try { 26 | const { name, founder } = req.body; 27 | const newHouse = await houseModel.createHouse(name, founder); 28 | res.status(201).json(newHouse); 29 | } catch (error) { 30 | res.status(500).json({ message: "Erro ao criar Casa!" }); 31 | } 32 | }; 33 | 34 | const updateHouse = async (req, res) => { 35 | try { 36 | const { name, founder } = req.body; 37 | const updateHouse = await houseModel.updateHouse(req.params.id, name, founder); 38 | if (!updateHouse) { 39 | return res.status(404).json({ message: "Casa não encontrado!" }); 40 | } 41 | res.json(updateHouse); 42 | } catch (error) { 43 | res.status(500).json({ message: "Erro ao atualizar Casa!" }); 44 | } 45 | }; 46 | 47 | const deleteHouse = async (req, res) => { 48 | try { 49 | const message = await houseModel.deleteHouse(req.params.id); 50 | res.json(message); 51 | } catch (error) { 52 | res.status(500).json({ message: "Erro ao deletar house." }); 53 | } 54 | }; 55 | 56 | module.exports = { getAllHouses, getHouse, createHouse, updateHouse, deleteHouse }; 57 | -------------------------------------------------------------------------------- /src/controllers/reportController.js: -------------------------------------------------------------------------------- 1 | const { format } = require("@fast-csv/format"); 2 | const PDFDocument = require("pdfkit"); 3 | const wizardModel = require("../models/wizardModel"); 4 | 5 | const exportWizardCSV = async (req, res) => { 6 | try { 7 | const wizards = await wizardModel.getWizards(); 8 | 9 | res.setHeader("Content-Disposition", "attachment; filename=wizards.csv"); 10 | res.setHeader("Content-Type", "text-csv"); 11 | 12 | const csvStream = format({ headers: true }); 13 | csvStream.pipe(res); 14 | 15 | wizards.forEach((wizard) => { 16 | csvStream.write({ 17 | Id: wizard.id, 18 | Nome: wizard.name, 19 | Casa: wizard.house_name || "Sem Casa" 20 | }); 21 | }); 22 | 23 | csvStream.end(); 24 | } catch (error) { 25 | res.status(500).json({ message: "Erro ao gerar o CSV" }); 26 | } 27 | }; 28 | 29 | const exportWizardPDF = async (req, res) => { 30 | try { 31 | const wizards = await wizardModel.getWizards(); 32 | 33 | res.setHeader("Content-Type", "application/pdf"); 34 | res.setHeader("Content-Disposition", "inline; filename=wizards.pdf") 35 | 36 | const doc = new PDFDocument(); 37 | doc.pipe(res); 38 | 39 | //Titulo 40 | doc.fontSize(20).text("Relatorio de Bruxos", { align: "center" }); 41 | doc.moveDown(); 42 | 43 | //Cabeçalho 44 | doc.fontSize(12).text("Id | Nome | Casa", { underline: true }); 45 | doc.moveDown(0.5); 46 | 47 | //Add dados dos bruxos 48 | wizards.forEach((wizard) => { 49 | doc.text( 50 | `${wizard.id} | ${wizard.name} | ${wizard.house_name} || "Sem Casa"` 51 | ); 52 | }); 53 | 54 | doc.end(); 55 | } catch (error) { 56 | res.status(500).json({ message: "Erro ao gerar PDF!" }); 57 | } 58 | }; 59 | 60 | module.exports = { exportWizardCSV, exportWizardPDF }; -------------------------------------------------------------------------------- /src/controllers/wizardController.js: -------------------------------------------------------------------------------- 1 | const wizardModel = require("../models/wizardModel"); 2 | 3 | const getAllWizards = async (req, res) => { 4 | try { 5 | const wizards = await wizardModel.getWizards(); 6 | res.json(wizards); 7 | } catch (error) { 8 | res.status(500).json({ message: "Erro ao buscar bruxos!" }); 9 | } 10 | }; 11 | 12 | const getWizard = async (req, res) => { 13 | try { 14 | const wizard = await wizardModel.getWizardById(req.params.id); 15 | if (!wizard) { 16 | return res.status(404).json({ message: "Bruxo não encontrado!" }); 17 | } 18 | res.json(wizard); 19 | } catch (error) { 20 | res.status(500).json({ message: "Erro ao buscar bruxo!" }); 21 | } 22 | }; 23 | 24 | const createWizard = async (req, res) => { 25 | try { 26 | const { name, house_id } = req.body; 27 | const photo = req.file ? req.file.filename : null; 28 | const newWizard = await wizardModel.createWizard(name, house_id, photo); 29 | res.status(201).json(newWizard); 30 | } catch (error) { 31 | res.status(500).json({ message: "Erro ao criar bruxo!" }); 32 | } 33 | }; 34 | 35 | const updateWizard = async (req, res) => { 36 | try { 37 | const { name, house_id } = req.body; 38 | const updateWizard = await wizardModel.updateWizard(req.params.id, name, house_id); 39 | if (!updateWizard) { 40 | return res.status(404).json({ message: "Bruxo não encontrado!" }); 41 | } 42 | res.json(updateWizard); 43 | } catch (error) { 44 | res.status(500).json({ message: "Erro ao atualizar Bruxo!" }); 45 | } 46 | }; 47 | 48 | const deleteWizard = async (req, res) => { 49 | try { 50 | const message = await wizardModel.deleteWizard(req.params.id); 51 | res.json(message); 52 | } catch (error) { 53 | res.status(500).json({ message: "Erro ao deletar Bruxo!" }); 54 | } 55 | }; 56 | 57 | module.exports = { getAllWizards, getWizard, createWizard, updateWizard, deleteWizard }; 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BackEnd-HarryPotter.SQLRelationships 2 | 3 | ## Descrição do Projeto 4 | 5 | Este projeto é uma API Back-End desenvolvida para gerenciar dados relacionados ao universo de Harry Potter. Ele utiliza relacionamentos SQL para estruturar e organizar as informações de forma eficiente, permitindo consultas e manipulações de dados relacionadas a personagens e casas! 6 | 7 | ## Funcionalidades 8 | 9 | - **Gerenciamento de Personagens**: CRUD completo para personagens, incluindo atributos como nome, casa, linhagem, etc. 10 | - **Casas de Hogwarts**: Relacionamento entre personagens e suas respectivas casas. 11 | - **Consultas Relacionais**: Consultas otimizadas para explorar as conexões entre diferentes entidades do universo de Harry Potter. 12 | - **Validação de Dados**: Garantia de integridade e consistência dos dados armazenados. 13 | 14 | ## Tecnologias Utilizadas 15 | 16 | - **Linguagem**: Node.js 17 | - **Banco de Dados**: MySQL com uso extensivo de relacionamentos (chaves primárias e estrangeiras). 18 | - **Framework**: Express.js para construção da API. 19 | - **Outras Ferramentas**: Postman para testes de API, dotenv para gerenciamento de variáveis de ambiente. 20 | 21 | ## Estrutura do Projeto 22 | 23 | - `/models`: Contém os modelos do banco de dados e suas associações. 24 | - `/routes`: Define as rotas da API para cada entidade. 25 | - `/controllers`: Contém a lógica de negócios para manipulação de dados. 26 | - `/config`: Configurações do banco de dados e variáveis de ambiente. 27 | 28 | ## Como Executar o Projeto 29 | 30 | 1. Clone o repositório: 31 | ```bash 32 | git clone https://github.com/seu-usuario/BackEnd-HarryPotter.SQLRelationships.git 33 | ``` 34 | 2. Instale as dependências: 35 | ```bash 36 | npm install 37 | ``` 38 | 3. Configure o arquivo `.env` com as credenciais do banco de dados. 39 | 4. Inicie o servidor: 40 | ```bash 41 | npm start 42 | ``` 43 | 44 | ## Contribuição 45 | 46 | Contribuições são bem-vindas! Siga os passos abaixo: 47 | 48 | 1. Faça um fork do repositório. 49 | 2. Crie uma branch para sua feature: 50 | ```bash 51 | git checkout -b minha-feature 52 | ``` 53 | 3. Faça o commit das suas alterações: 54 | ```bash 55 | git commit -m "Minha nova feature" 56 | ``` 57 | 4. Envie para o repositório remoto: 58 | ```bash 59 | git push origin minha-feature 60 | ``` 61 | 5. Abra um Pull Request. 62 | 63 | ## Licença 64 | 65 | Este projeto está licenciado sob a [MIT License](LICENSE). 66 | 67 | ## Contato 68 | 69 | Para dúvidas ou sugestões, entre em contato pelo e-mail: `enzoturcovic@gmail.com`. 70 | --------------------------------------------------------------------------------