{"id":30111285,"url":"https://github.com/viniciusleonel/first-ruby-api","last_synced_at":"2026-04-13T04:44:00.018Z","repository":{"id":263185142,"uuid":"889608377","full_name":"viniciusleonel/first-ruby-api","owner":"viniciusleonel","description":"Esta API foi desenvolvida para integrar dois sistemas, permitindo a transformação de um arquivo de pedidos desnormalizado proveniente de um sistema legado em um arquivo JSON normalizado.","archived":false,"fork":false,"pushed_at":"2025-08-08T19:41:40.000Z","size":410,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-08T21:25:57.037Z","etag":null,"topics":["azure","docker","github-actions","postgresql","rspec","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/viniciusleonel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-11-16T18:58:17.000Z","updated_at":"2025-08-08T19:41:44.000Z","dependencies_parsed_at":"2025-08-08T21:11:48.148Z","dependency_job_id":"f1552495-9d27-4cc5-b9aa-3d15d3c0552d","html_url":"https://github.com/viniciusleonel/first-ruby-api","commit_stats":null,"previous_names":["viniciusleonel/first-ruby-api"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/viniciusleonel/first-ruby-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viniciusleonel%2Ffirst-ruby-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viniciusleonel%2Ffirst-ruby-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viniciusleonel%2Ffirst-ruby-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viniciusleonel%2Ffirst-ruby-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/viniciusleonel","download_url":"https://codeload.github.com/viniciusleonel/first-ruby-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viniciusleonel%2Ffirst-ruby-api/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269683153,"owners_count":24458625,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azure","docker","github-actions","postgresql","rspec","ruby"],"created_at":"2025-08-10T06:00:45.264Z","updated_at":"2026-04-13T04:43:54.982Z","avatar_url":"https://github.com/viniciusleonel.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Documentação do Projeto\n\nEste projeto é uma API simples desenvolvida em Ruby, utilizando PostgreSQL como banco de dados e Docker para containerização, com um pipeline de CI/CD utilizando GitHub Actions que automatiza a validação de código, testes, criação de imagens Docker e implantação contínua no Azure, garantindo entregas rápidas, confiáveis e seguras.\n\nEsta API foi desenvolvida para integrar dois sistemas, permitindo a transformação de um arquivo de pedidos desnormalizado proveniente de um sistema legado em um arquivo JSON normalizado. A API oferece funcionalidades para acessar e gerenciar dados de pedidos, incluindo a capacidade de realizar consultas gerais e aplicar filtros específicos, como:\n\n- **ID do pedido**: possibilitando a busca de um pedido específico.\n- **Intervalo de data de compra**: permitindo filtrar pedidos com base em um intervalo de datas definido (data de início e data de fim).\n- **Paginação**: possibilitando a listagem de pedidos em páginas, facilitando a navegação por grandes volumes de dados.\n- **Verificação do documento enviado**: garantindo que o arquivo de pedidos enviado atenda ao formato esperado e contenha os dados necessários para processamento. A validação inclui:\n  - **Comprimento da linha**: cada linha do arquivo deve ter exatamente 95 caracteres.\n  - **Formato dos campos**: os campos devem seguir as seguintes regras:\n    - **ID do usuário**: deve ser um número de 10 dígitos.\n    - **Nome do usuário**: deve ter no máximo 45 caracteres e conter apenas letras e espaços.\n    - **ID do pedido**: deve ser um número de 10 dígitos.\n    - **ID do produto**: deve ser um número de 10 dígitos.\n    - **Valor**: deve ser um número decimal com até duas casas decimais.\n    - **Data**: deve estar no formato `YYYYMMDD`.\n  - **Tratamento de erros**: se o arquivo não atender a qualquer uma dessas condições, a API retornará um erro informando a linha e o problema específico encontrado.\n\n\nEssas funcionalidades garantem uma manipulação eficiente dos dados de pedidos, facilitando a integração e a análise das informações.\n\n\u003c!--\n[Link deploy Azure](https://luizalabs-ruby-a7dghshjbkcahyg3.eastus-01.azurewebsites.net/)--\u003e\n\n---\n\n## Tecnologias Utilizadas\n\nEste projeto utiliza as seguintes tecnologias e ferramentas:\n\n- **Ruby**: A linguagem de programação utilizada para desenvolver a API.\n- **Rack**: Gem que fornece uma interface modular para servidores web e aplicações Ruby, facilitando a construção de aplicações web.\n- **PostgreSQL**: O sistema de gerenciamento de banco de dados relacional utilizado para armazenar os dados.\n- **Docker**: Ferramenta de containerização que permite empacotar a aplicação e suas dependências em um ambiente isolado.\n- **Docker Compose**: Utilizado para definir e executar aplicações Docker multi-container.\n- **RSpec**: Framework de testes para Ruby, utilizado para garantir a qualidade e a confiabilidade do código.\n- **Async**: Gem utilizada para processamento assíncrono, permitindo que a API continue respondendo a novas requisições enquanto processa dados em segundo plano.\n- **GitHub Actions**: Ferramenta de integração contínua e entrega contínua (CI/CD) que automatiza o processo de deploy da aplicação.\n- **Microsoft Azure**: Plataforma de nuvem utilizada para hospedar a aplicação em produção.\n\nEssas tecnologias foram escolhidas para garantir a escalabilidade, a eficiência e a facilidade de manutenção da API.\n\n---\n\n## Pré-requisitos\n\n- Docker e Docker Compose instalados em sua máquina.\n- Ruby (versão 3.1 ou superior) instalado.\n- Clonar este repositório: https://github.com/viniciusleonel/first-ruby-api\n\n---\n\n## Configurações da API\n\n**Esta API possui quatro configurações:**\n\n### 1. Rodar toda a aplicação em um container (API + Banco de dados)\n- Requisito: **Precisa ter o Docker e Docker Compose instalados.**\n- No seu arquivo `.env`, crie uma variável de ambiente `PROFILE` o valor `development`\n- Insira o link de conexão na variável de ambiente `DATABASE_LOCAL_URL` com o valor `postgres://postgres:123456@db:5432/luizalabs` no arquivo `.env`\n\n- Crie a imagem da aplicação executando o seguinte comando abaixo:\n\n   ```bash\n   docker-compose -f docker-compose.local.yml build\n   ```\n\n- Execute o seguinte comando para iniciar os containers do PostgreSQL e da aplicação:\n\n   ```bash\n   docker-compose -f docker-compose.local.yml up -d\n   ```\n\n[//]: # (- Em um único comando `powershel`:)\n\n[//]: # (   ```bash)\n\n[//]: # (   docker-compose -f docker-compose.local.yml build; docker-compose -f docker-compose.local.yml up -d)\n\n[//]: # (   ```)\n\n[//]: # (- Em um único comando`bash`)\n\n[//]: # (  ```bash)\n\n[//]: # (   docker-compose -f docker-compose.local.yml build \u0026\u0026 docker-compose -f docker-compose.local.yml up -d)\n\n[//]: # (   ```)\n\nIsso irá criar primeiro um container com um banco de dados PostgreSQL (cria automaticamente a database para a aplicação).\n\nEm seguida irá criar o container para a aplicação, executando automaticamente as migrations, o `bundle install` e o `rackup`.\n\nA aplicação estará disponível em `http://localhost:9292`.\n\n### 2. API em produção utilizando GitHub Actions, DockerHub e MicrosoftAzure\n- Esta configuração é específica para rodar a API em produção, ela utiliza as configurações do arquivo arquivo [continuous delivery](.github/workflows/continuous_delivery.yml),\n  fazendo uma integração contínua e deploy automatizado utilizando **GitHub Actions**, **DockerHub** e **Microsoft Azure**.\n\n***Link desativado devido a descontinuação dos benefícios do plano gratuito da conta Azure.***\n\nhttps://luizalabs-ruby-a7dghshjbkcahyg3.eastus-01.azurewebsites.net/\n\n### 3. Rodar a API em uma IDEA de sua escolha com um banco de dados PostgreSQL(Container ou nuvem).\n- Requisito: **Precisa ter o Ruby instalado.**\n- Dentro da sua plataforma de deploy, crie uma variável de ambiente `PROFILE` o valor `development`\n- Substitua o link de conexão na var de ambiente `DATABASE_PROD_URL` do [arquivo .env](.env)\n- Instale as dependências executando o seguinte comando no diretório raiz do projeto:\n\n   ```bash\n   bundle install\n   ```\n- Inicie a aplicação executando o seguinte comando no diretório raiz do projeto:\n  (as migrations serão feitas automaticamente)\n\n   ```bash\n   rackup\n   ```\n\n### 4. AMBIENTE DE TESTES - Esta configuração vai ser descrita na parte de TESTES\n\n---\n\n## Fluxo da API\n\nA API foi projetada para gerenciar dados de usuários, pedidos e produtos, possibilitando operações como listagem, criação e upload de arquivos. O fluxo detalhado da API é descrito abaixo:\n\n1. **Envio e Validação de Arquivos**:\n- Quando um arquivo `.txt` é enviado para o endpoint `/upload` através de uma requisição POST, a API, por meio do `FileController`, realiza a verificação dos parâmetros, garantindo que a chave e o nome do arquivo estejam corretos e que o arquivo tenha sido enviado corretamente.\n- Após a validação, o `FileService` lê o conteúdo do arquivo e o salva temporariamente em um local seguro, retornando os dados do arquivo na resposta.\n\n2. **Processamento Assíncrono do Arquivo**:\n- Uma vez armazenado, a API inicia um processo de processamento assíncrono em segundo plano, utilizando threads e a `gem` `Async`. O método `FileService.save_data_to_db(file_path, filename)` é executado para ler o conteúdo do arquivo e persistir os dados no banco de dados.\n- Este processo assíncrono permite que a API continue respondendo a novas requisições sem bloqueios, garantindo que operações intensivas, como a gravação em banco de dados, não afetem a performance da aplicação.\n- Após o término do processamento e da gravação dos dados, o arquivo é excluído do armazenamento temporário para liberar espaço e manter a segurança dos dados.\n- Pode-se obter informações sobre o processamento do arquivo no terminal, confirmando que foi armazenado e deletado com sucesso.\n\n3. **Consulta de Dados Salvos**:\n- O endpoint `/` é responsável por retornar os dados que foram salvos no banco de dados. Ele suporta paginação por meio dos parâmetros `page` e `size`  retornando informações como a página atual, o tamanho da página, o total de páginas e o total de dados armazenados.\n- O endpoint `/files` é responsável por retornar os nomes dos arquivos que já foram enviados na API. Ele suporta paginação por meio dos parâmetros `page` e `size`  retornando informações como a página atual, o tamanho da página, o total de páginas e o total de dados armazenados.\n- O endpoint `/orders` permite a listagem de pedidos com suporte a paginação e filtros por data, utilizando os parâmetros `start_date` e `end_date` no formato `YYYY-MM-DD`. A ordenação padrão para este endpoint é por data, facilitando a busca de pedidos em um intervalo específico.\n- O endpoint `/order/:id` permite a consulta de um pedido específico pelo seu identificador único (`id`), retornando detalhes completos sobre o pedido, incluindo informações associadas.\n\nVocê pode testar a API utilizando ferramentas como o Insomnia ou Postman.\n\n---\n\n## Endpoints\n### Endpoint \"/upload\"\n\n- **POST**: Endpoint para envio do arquivo `.txt`\n  - **Descrição**: Este endpoint permite que o cliente envie um arquivo `.txt` que será salvo temporariamente no servidor.\n\n  **Parâmetros da Requisição**:\n  - O arquivo deve ser enviado no `body` como parte de um formulário `multipart/form-data` com o campo `file`.\n\n  **Exemplo de Requisição**:\n\n  Para fazer a requisição de envio do arquivo, você pode usar o `cURL` ou ferramentas como Postman e Insomnia.\n\n\n  **Usando o Postman**:\n  1. Selecione o método `POST`.\n  2. Insira a URL `http://localhost:9292/upload`.\n  3. Vá para a aba `Body` e selecione `form-data`.\n  4. Adicione um campo com as seguintes configurações:\n    - **Key (name)**: `file`\n    - **Type**: Marque como `File`\n    - **Content-Type**: Defina como `multipart/form-data`\n  5. Selecione o arquivo `.txt` desejado no seu computador.\n  6. Clique em `Send`.\n\n---\n\n  **Respostas Esperadas**:\n  - **201 Created**: Se o arquivo for recebido e salvo com sucesso.\n    ```json\n      [\n        {\n          \"user_id\":1,\n          \"name\":\"Zarelli\",\n          \"orders\":[\n            {\n              \"order_id\":123,\n              \"total\":\"1024.48\",\n              \"date\":\"2021-12-01\",\n              \"products\":[\n                {\n                  \"product_id\":111,\n                  \"value\":\"512.24\"\n                },\n                {\n                  \"product_id\":122,\n                  \"value\":\"512.24\"\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"user_id\":2,\n          \"name\":\"Medeiros\",\n          \"orders\":[\n            {\n              \"order_id\":12345,\n              \"total\":\"512.48\",\n              \"date\":\"2020-12-01\",\n              \"products\":[\n                {\n                  \"product_id\":111,\n                  \"value\":\"256.24\"\n                },\n                {\n                  \"product_id\":122,\n                  \"value\":\"256.24\"\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    ```\n    **Tratamento de Erros**:\n    - **400 Bad Request**: Se o arquivo não for fornecido ou se houver um erro durante o upload (por exemplo, key ou name inválidos).\n      ```json\n      {\n        \"error\": \"File not provided\" \n      }\n      ```\n      - **400 Bad Request**: Se o arquivo já estiver sido salvo no banco de dados. (Salva somente o nome na tabela `files`)\n      ```json\n      {\n      \"error\": \"An error occurred while processing the file: File 'data_1' already exists in database!\"\n      }\n      ```\n    - **400 Bad Request**: Se o arquivo não for do formato `.txt`.\n      ```json\n      {\n          \"error\": \"Invalid file type. Only .txt files are allowed.\"\n      }\n      ```\n    - **400 Bad Request**: Se o arquivo for do formato `.txt` mas não for do padrão esperado pela API.\n      ```json\n      {\n      \"error\": \"An error occurred while processing the file: Error in line 1: Line has invalid length: 63 characters\"\n      }\n      ```\n      Outro exemplo:\n      ```json\n      {\n      \"error\": \"An error occurred while processing the file: Error in line 2: Error in line format: Invalid user name\"\n      }\n      ```\n\n---\n\n### Endpoint \"/\"\n\n- **GET**: Endpoint para listagem de todos os dados como:\n  - Aceita filtros de paginação: `/?page=1\u0026size=5`\n  - Paginação padrão por nome\n     ```json\n     {\n       \"users\": [\n         {\n           \"user_id\": \"123\",\n           \"name\": \"John Doe\",\n           \"orders\": [\n             {\n               \"order_id\": \"456\",\n               \"file_id\": \"1\", \n               \"total\": 200.50,\n               \"date\": \"2024-11-15\",\n               \"products\": [\n                 {\n                   \"product_id\": \"789\",\n                   \"value\": 100.25\n                 }\n               ]\n             }\n           ]\n         }\n       ],\n       \"page\": 1,\n       \"size\": 5,\n       \"total_users\": 100,\n       \"total_pages\": 20\n     }\n     ```\n  - Caso não tenha dados no bando de dados:\n    ```json\n    {\n      \"data\": [],\n      \"page\": 1,\n      \"size\": 5,\n      \"total_users\": 0,\n      \"total_pages\": 0\n    }\n    ```\n\n---\n\n### Endpoint \"/orders\"\n\n- **GET**: Endpoint para listagem de todos os pedidos:\n  - Aceita filtros de paginação: `?page=1\u0026size=1`\n  - Aceita paginação com intervalo de data de compra (data início e data fim) `?start_date=YYYY-mm-dd\u0026end_date=YYYY-mm-dd`\n  - Paginação padrão por data\n  ```json\n    {\n      \"orders\": [\n        {\n          \"order_id\": \"523\",\n          \"file_id\": \"1\",\n          \"user_id\": \"49\",\n          \"total\": \"586.74\",\n          \"date\": \"2021-09-03\",\n          \"products\": [\n            {\n              \"value\": 586.74,\n              \"product_id\": 3\n            }\n          ]\n        },\n        {\n          \"order_id\": \"620\",\n          \"file_id\": \"1\",\n          \"user_id\": \"57\",\n          \"total\": \"1417.25\",\n          \"date\": \"2021-09-19\",\n          \"products\": [\n            {\n              \"value\": 1417.25,\n              \"product_id\": 0\n            }\n          ]\n        }\n      ],\n      \"page\": 1,\n      \"size\": 1,\n      \"total_orders\": 1084,\n      \"total_pages\": 1084\n    }\n  ```\n  - Caso não tenha dados no bando de dados:\n  ```json\n  {\n    \"orders\": [],\n    \"page\": 1,\n    \"size\": 1,\n    \"total_orders\": 0,\n    \"total_pages\": 0\n  }\n  ```\n\n---\n\n### Endpoint \"/orders/:id\"\n\n- **GET**: Endpoint para buscar pedido por id:\n\n  ```json\n  {\n    \"order_id\": \"753\",\n    \"file_id\": \"1\",\n    \"user_id\": \"70\",\n    \"total\": \"787.46\",\n    \"date\": \"2021-03-08\",\n    \"products\": [\n      {\n        \"value\": 1836.74,\n        \"product_id\": 3\n      },\n      {\n        \"value\": 1009.54,\n        \"product_id\": 3\n      },\n      {\n        \"value\": 618.79,\n        \"product_id\": 4\n      },\n      {\n        \"value\": 787.46,\n        \"product_id\": 3\n      }\n    ]\n  }\n  ```\n\n  **Tratamento de Erros**:\n  - **400 Bad Request**: Caso `id` fornecido não seja encontrado\n  ```json\n  {\n    \"error\": \"Order Not Found\"\n  }\n  ```\n\n---\n\n### Endpoint \"/files\"\n\n- **GET**: Endpoint para buscar os arquivos salvos:\n\n    ```json\n    {\n    \"files\": [\n      {\n        \"file_id\": \"1\",\n        \"name\": \"data_1\",\n        \"date\": \"2024-11-22 20:37:47\"\n      },\n      {\n        \"file_id\": \"2\",\n        \"name\": \"data_2\",\n        \"date\": \"2024-11-22 20:37:53\"\n      }\n     ],\n      \"page\": 1,\n      \"size\": 5,\n      \"total_files\": 8,\n      \"total_pages\": 2\n    }\n    ```\n\n---\n\n### **Todos Endpoints possuem tratamento de erro para a rota e metódo:**\n- **400 Bad Request**:\n    ```json\n    {\n      \"error\": \"Endpoint not Found\"\n    }\n    ```\n- **400 Bad Request**:\n  ```json\n  {\n    \"error\": \"Method Not Allowed\"\n  }\n  ```\n    \n---\n\n## Testes (Necessário a configuração de AMBIENTE DE TESTES!)\n\nA qualidade do código é garantida por meio de testes automatizados com RSpec, localizados no diretório `spec`, que cobrem as funcionalidades essenciais da API.\n\n### Executando os Testes\n\n###  AMBIENTE DE TESTES - Rodar toda a aplicação em um container (API + Banco de dados)\n- Requisito: Precisa ter o Docker e Docker Compose instalados.\n- No seu arquivo `.env`, crie uma variável de ambiente `PROFILE` e insira o valor `test`.\n- Insira o link de conexão na variável de ambiente `DATABASE_TEST_URL` com o valor `postgres://postgres:123456@localhost/luizalabs_test` no arquivo `.env`\n\n- Execute o seguinte comando para iniciar o container do banco de dados de testes PostgreSQL:\n\n   ```bash\n   docker-compose -f docker-compose.test.yml up -d\n   ```\n\n- Instale as dependências executando o seguinte comando no diretório raiz do projeto:\n\n   ```bash\n   bundle install\n   ```\n\n[//]: # (- Inicie a aplicação executando o seguinte comando no diretório raiz do projeto:)\n\n[//]: # (  \u0026#40;as migrations serão feitas automaticamente\u0026#41;)\n\n[//]: # ()\n[//]: # (   ```bash)\n\n[//]: # (   rackup)\n\n[//]: # (   ```)\n\n- Execute os testes com o seguinte comando:\n   ```bash\n  bundle exec rspec\n   ```\n\n---\n\n## Estrutura dos Testes\n\n- **Gems e Configurações**\n  - `Rack::Test`: Utilizado para simular requisições HTTP e verificar as respostas.\n  - `Application`: A classe principal que gerencia as rotas da aplicação.\n  - **spec/controllers**: Diretório que contém os testes para os controladores, assegurando que as requisições sejam processadas corretamente e as respostas estejam no formato esperado.\n\nEste teste usa o RSpec em conjunto com o módulo Rack::Test para \nsimular requisições HTTP e validar se os controladores da aplicação \nestão processando as rotas corretamente, retornando os status e \nconteúdos esperados para cada tipo de requisição.\n\n---\n\n## Descrição do Teste: `FileController`\n\nEste teste verifica o comportamento do `FileController`, que gerencia \no upload de arquivos e a recuperação de informações sobre arquivos. \nO teste cobre cenários como envio de arquivos .txt válidos, ausência \nde arquivos, arquivos com formato inválido, arquivos com dados \nincorretos e a recuperação de dados sobre arquivos enviados. \nEle garante que a API responda corretamente a diferentes tipos \nde requisições e erros, retornando os status e mensagens apropriadas.\n\n## Cenários de Teste\n\n### 1. **Envio de um arquivo .txt válido**\n- **Descrição**: Quando um arquivo [.txt](challenge/data_1.txt) válido é enviado retorna um status 201 e dados em formato JSON.\n- **Requisição**: `POST /upload` com um arquivo anexado.\n- **Expectativas**:\n  - Status HTTP: **201 Created**.\n  - `Content-Type`: **application/json**.\n  - O arquivo é salvo no diretório configurado.\n  - Verifica se a resposta da API está conforme as expectativas.\n\n### 2. **Envio Sem Arquivo**\n- **Descrição**: Nenhum arquivo é enviado na requisição.\n- **Requisição**: `POST /upload` sem parâmetros.\n- **Expectativas**:\n  - Status HTTP: **400 Bad Request**.\n  - Corpo da resposta inclui a mensagem: \"File not provided\".\n  \n### 3. **Envio de um arquivo com formato inválido (Arquivo que não seja .txt)**\n- **Descrição**: Um arquivo [.pdf](challenge/Desafio%20técnico%20-%20Vertical%20Logistica.pdf) é enviado na requisição.\n- **Requisição**: `POST /upload` com um arquivo .pdf anexado.\n- **Expectativas**:\n  - Status HTTP: **400 Bad Request**.\n  - Corpo da resposta inclui a mensagem: \"Invalid file type. Only .txt files are allowed.\".\n\n### 4. **Envio de um arquivo .txt com padrão fora do esperado**\n- **Descrição**: Um arquivo [.txt](spec/fixtures/invalid-data.txt) com um texto comum é enviado na requisição.\n- **Requisição**: `POST /upload` com um arquivo anexado.\n- **Expectativas**:\n  - Status HTTP: **400 Bad Request**.\n  - Corpo da resposta inclui a mensagem: \"An error occurred while processing the file: Error in line 1: Line has invalid length: 63 characters\".\n\n### 5. **Envio de um arquivo .txt com formato padrão porém falta dados**\n- **Descrição**: Um arquivo [.txt](spec/fixtures/invalid-data_2.txt) com dados faltando é enviado na requisição.\n- **Requisição**: `POST /upload` sem parâmetros.\n- **Expectativas**:\n  - Status HTTP: **400 Bad Request**.\n  - Corpo da resposta inclui a mensagem: \"An error occurred while processing the file: Error in line 2: Error in line format: Invalid user name\".\n\n### 6. **Retorno de Dados Válidos**\n- **Descrição**: Este teste verifica se a requisição GET para o endpoint `/files` retorna um status 200 e dados em formato JSON.\n- **Requisição**: `GET /files?page=1\u0026size=5`.\n- **Expectativas**:\n  - O status da resposta deve ser 200.\n  - O tipo de conteúdo da resposta deve ser `application/json`.\n  - A resposta JSON deve conter as chaves:\n    - `files`\n    - `page`\n    - `size`\n    - `total_files`\n    - `total_pages`\n\n---\n\n## Descrição do Teste: `ApiController`\n\nEste teste avalia o comportamento do `ApiController`, cobrindo dois cenários principais: \nvalida se endpoints inválidos retornam um `status 404` com a mensagem de erro adequada e assegura que \no endpoint raiz (`GET /`) responde com `status 200`, retornando dados \nestruturados no formato `JSON` com informações como `data`, `page`, `size`, \n`total_users` e `total_pages`. Esse processo garante a integridade e \nconfiabilidade das respostas da API conforme o esperado.\n\n## Cenários de Teste\n\n### 1. **Retorno de Dados Válidos**\n- **Descrição**: Este teste verifica se a requisição GET para o endpoint `/` retorna um status 200 e dados em formato JSON.\n- **Requisição**: `GET /?page=1\u0026size=5`\n- **Expectativas**:\n  - O status da resposta deve ser 200.\n  - O tipo de conteúdo da resposta deve ser `application/json`.\n  - A resposta JSON deve conter as chaves:\n    - `data`\n    - `page`\n    - `size`\n    - `total_users`\n    - `total_pages`\n\n### 2. **Requisição para endpoint inválido**\n- **Descrição**: Este teste retorna uma mensagem de erro se o endpoint na requisição for inválido.\n- **Requisição**: `GET /invalido`\n- **Expectativas**:\n  - Status HTTP: **404 Not Found**.\n  - Corpo da resposta inclui a mensagem: \"Endpoint Not Found\".\n\n---\n\n## Descrição do Teste: `OrderController`\n\nEste teste avalia o comportamento do `OrderController`, responsável \npor gerenciar e processar requisições relacionadas aos pedidos na \naplicação. O teste cobre três cenários principais: verifica se o \nendpoint `/orders` retorna `status 200` e dados em formato `JSON` com \ninformações como `orders`, `page`, `size`, `total_orders` e `total_pages`; \nassegura que o endpoint `/orders/:id` retorne os detalhes do pedido, \nincluindo `order_id`, `file_id`, `user_id`, `total`, `date` e `products` quando \num `ID` válido é fornecido; e valida que um `ID` de pedido inexistente \nresulta em um `status 404` com a mensagem de erro apropriada, garantindo \nque o sistema lida corretamente com diferentes tipos de requisição e \nretorno.\n\n## Cenários de Teste\n\n### 1. **Retorno de Pedidos Válidos**\n- **Descrição**: Este teste verifica se a requisição GET para o endpoint `/orders` retorna um status 200 e dados em formato JSON.\n- **Requisição**: `GET /orders`\n- **Expectativas**:\n  - O status da resposta deve ser 200.\n  - O tipo de conteúdo da resposta deve ser `application/json`.\n  - A resposta JSON deve conter as chaves:\n    - `orders`\n    - `page`\n    - `size`\n    - `total_orders`\n    - `total_pages`\n\n### 2. **Retorno de Pedido Específico**\n- **Descrição**: Este teste verifica se a requisição GET para o endpoint `/orders/:id` retorna um status 200 e o pedido específico em formato JSON.\n- **Requisição**: `GET /orders/:id`\n- **Expectativas**:\n  - O status da resposta deve ser 200.\n  - O tipo de conteúdo da resposta deve ser `application/json`.\n  - A resposta JSON deve conter as chaves:\n    - `order_id`\n    - `file_id`\n    - `user_id`\n    - `total`\n    - `date`\n    - `products`\n\n### 3. **Retorno de Pedido Inexistente**\n- **Descrição**: Este teste verifica se a requisição GET para o endpoint `/orders/:id` retorna um status 404 quando o pedido especificado não existe.\n- **Requisição**: `GET /orders/:id` com um ID inválido.\n- **Expectativas**:\n  - O status da resposta deve ser 404.\n  - O corpo da resposta deve incluir a mensagem: \"Order not found\".\n\n---\n\n## Continuous Delivery Workflow \n\n### Descrição\nEste workflow configura um processo de Continuous Delivery (CD) para uma aplicação Ruby utilizando GitHub Actions. Ele realiza testes automatizados, cria e envia uma imagem Docker para o Docker Hub e realiza o deploy em uma Azure Web App.\n\n---\n\n### Gatilho\nO workflow é acionado automaticamente para qualquer push na branch `main`.\n\n---\n\n## Estrutura do Workflow\n\n### Jobs\n\n### 1. Build\n#### Responsabilidade\nConfigurar o ambiente, rodar os testes automatizados, criar uma imagem Docker e enviá-la para o Docker Hub.\n\n#### Executado em\nUbuntu-latest.\n\n#### Etapas\n1. **Checkout do Código**\n  - Baixa o código da branch `main` do repositório.\n\n2. **Configuração do Ruby**\n  - Configura a versão do Ruby 3.1 para execução do projeto.\n\n3. **Instalação das Dependências**\n  - Executa `bundle install` para instalar as dependências Ruby definidas no `Gemfile`.\n\n4. **Instalação do Docker e Docker Compose**\n  - Instala Docker e Docker Compose para suporte à execução de containers.\n\n5. **Inicialização do Banco de Dados de Teste**\n  - Executa o arquivo `docker-compose.test.yml` para subir um container PostgreSQL para testes.\n\n6. **Espera pelo PostgreSQL**\n  - Aguarda o banco de dados estar pronto com o comando `pg_isready`.\n\n7. **Execução dos Testes**\n  - Roda os testes automatizados com `bundle exec rspec`.\n\n8. **Login no Docker Hub**\n  - Realiza login no Docker Hub utilizando credenciais armazenadas nos secrets (`DOCKERHUB_USERNAME` e `DOCKERHUB_TOKEN`).\n\n9. **Build e Push da Imagem Docker**\n  - Cria a imagem Docker utilizando o `Dockerfile`, com uma tag baseada no SHA do commit, e a envia para o Docker Hub.\n\n---\n\n### 2. Deploy\n#### Responsabilidade\nRealizar o deploy da aplicação na Azure Web App usando a imagem Docker criada.\n\n#### Executado em\nUbuntu-latest.\n\n#### Dependência\nExecutado apenas após o sucesso do job `build`.\n\n#### Etapas\n1. **Deploy para a Azure Web App**\n  - Realiza o deploy da imagem Docker utilizando a ação `azure/webapps-deploy@v2`.\n  - Configurações:\n    - `app-name`: Nome do aplicativo na Azure Web App (`luizalabs-ruby`).\n    - `slot-name`: Nome do slot de produção (`production`).\n    - `publish-profile`: Perfil de publicação armazenado em secrets (`AZURE_PROFILE`).\n    - `images`: Imagem Docker criada no job `build`.\n\n---\n\n### Variáveis de Ambiente\n- `DATABASE_TEST_URL`: String de conexão com o banco de dados PostgreSQL para testes.\n- `PROFILE`: Define o perfil de execução como `test`.\n\n---\n\n### Secrets Utilizados\n- `DOCKERHUB_USERNAME`: Usuário do Docker Hub.\n- `DOCKERHUB_TOKEN`: Token de autenticação no Docker Hub.\n- `AZURE_PROFILE`: Credenciais para deploy na Azure Web App.\n\n---\n\n### Arquivos Utilizados\n- **`docker-compose.test.yml`**\n  - Configuração do container de banco de dados para testes.\n- **`Dockerfile`**\n  - Configuração da imagem Docker da aplicação.\n\n---\n\n### Resultado Esperado\n1. **Build e Testes:**\n  - Testes automatizados executados com sucesso.\n  - Imagem Docker criada e enviada ao Docker Hub.\n2. **Deploy:**\n  - Aplicação implantada no ambiente de produção da Azure Web App utilizando a imagem Docker mais recente.\n\n---\n\n## Continuous Integration Workflow\n\n### Descrição\nEste workflow configura um processo de Continuous Integration (CI) para validar as alterações realizadas no código da aplicação Ruby. Ele é acionado por pull requests e executa testes automatizados para garantir a integridade e funcionalidade da aplicação.\n\n---\n\n### Gatilho\nO workflow é acionado automaticamente para cada `pull_request` no repositório.\n\n---\n\n## Estrutura do Workflow\n\n### Jobs\n\n### 1. Build\n#### Responsabilidade\nConfigurar o ambiente, executar testes automatizados e verificar a integridade da aplicação.\n\n#### Executado em\nUbuntu-latest.\n\n#### Etapas\n1. **Checkout do Código**\n  - Baixa o código atualizado da branch relacionada ao `pull_request`.\n\n2. **Configuração do Ruby**\n  - Configura a versão do Ruby 3.1 para execução do projeto.\n\n3. **Instalação das Dependências**\n  - Executa `bundle install` para instalar as dependências Ruby definidas no `Gemfile`.\n\n4. **Instalação do Docker e Docker Compose**\n  - Instala Docker e Docker Compose para suporte à execução de containers.\n\n5. **Inicialização do Banco de Dados de Teste**\n  - Executa o arquivo `docker-compose.test.yml` para subir um container PostgreSQL para testes.\n\n6. **Espera pelo PostgreSQL**\n  - Aguarda o banco de dados estar pronto com o comando `pg_isready`.\n\n7. **Execução dos Testes**\n  - Roda os testes automatizados com `bundle exec rspec`.\n\n---\n\n### Variáveis de Ambiente\n- `DATABASE_TEST_URL`: String de conexão com o banco de dados PostgreSQL para testes.\n- `PROFILE`: Define o perfil de execução como `test`.\n\n---\n\n### Arquivos Utilizados\n- **`docker-compose.test.yml`**\n  - Configuração do container de banco de dados para testes.\n\n---\n\n### Resultado Esperado\n1. Testes automatizados executados com sucesso para validar as alterações realizadas.\n2. Notificação sobre possíveis falhas para correção antes da aprovação do pull request.\n\n---\n\n## Conclusão\n\n\nA API desenvolvida oferece uma solução robusta e eficiente para a integração e gerenciamento de dados de pedidos, permitindo a transformação de arquivos desnormalizados em um formato JSON estruturado. Com funcionalidades como validação de arquivos, processamento assíncrono e suporte a consultas filtradas, a API garante uma experiência de usuário fluida e responsiva.\n\nA utilização de tecnologias modernas, como Docker e PostgreSQL, assegura a escalabilidade e a facilidade de manutenção do sistema. Além disso, a implementação de CI/CD com GitHub Actions e Azure permite um fluxo de trabalho contínuo e automatizado, facilitando o deploy e a integração de novas funcionalidades de forma rápida e segura. Essa abordagem não apenas melhora a eficiência do desenvolvimento, mas também garante que a aplicação esteja sempre atualizada e em conformidade com as melhores práticas.\n\nA implementação de testes automatizados com RSpec contribui para a confiabilidade e a qualidade do código, permitindo que a API se adapte a futuras necessidades e evoluções. Com isso, a API se posiciona como uma ferramenta valiosa para empresas que buscam otimizar seus processos de gestão de pedidos e dados, promovendo uma integração eficaz entre sistemas legados e novas soluções.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fviniciusleonel%2Ffirst-ruby-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fviniciusleonel%2Ffirst-ruby-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fviniciusleonel%2Ffirst-ruby-api/lists"}