{"id":21861484,"url":"https://github.com/ozmap/technical-assessment","last_synced_at":"2025-04-14T19:36:19.718Z","repository":{"id":42065341,"uuid":"428835055","full_name":"ozmap/technical-assessment","owner":"ozmap","description":"Technical assessment for the position of software engineer at DevOZ.","archived":false,"fork":false,"pushed_at":"2022-11-23T17:50:57.000Z","size":1631,"stargazers_count":0,"open_issues_count":1,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-28T08:01:43.562Z","etag":null,"topics":["assessment-project","challenge","data-structures","restful-api","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ozmap.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-16T22:36:44.000Z","updated_at":"2021-12-30T01:32:40.000Z","dependencies_parsed_at":"2022-08-12T03:50:52.149Z","dependency_job_id":null,"html_url":"https://github.com/ozmap/technical-assessment","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozmap%2Ftechnical-assessment","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozmap%2Ftechnical-assessment/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozmap%2Ftechnical-assessment/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ozmap%2Ftechnical-assessment/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ozmap","download_url":"https://codeload.github.com/ozmap/technical-assessment/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248946835,"owners_count":21187583,"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","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":["assessment-project","challenge","data-structures","restful-api","typescript"],"created_at":"2024-11-28T03:11:46.863Z","updated_at":"2025-04-14T19:36:19.696Z","avatar_url":"https://github.com/ozmap.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Avaliação Técnica\n\n\u003ca id=\"sumario\"\u003e\u003c/a\u003e\n## 0. Sumário\n\n\u003c!-- TOC --\u003e\n  * [Introdução](#introducao)\n  * [O desafio](#odesafio)\n    * [Parte 1: API de usuários](#parteum)\n    * [Parte 2: Agregador de URLs](#partedois)\n  * [Submissão da solução](#submissao)\n\u003c!-- /TOC --\u003e\n\n\u003ca id=\"introducao\"\u003e\u003c/a\u003e\n## 1. Introdução\n\nO teor deste desafio é bastante voltado a alguns problemas que resolvemos com frequência, e vai nos ajudar a descobrir como você raciocina e quais são suas habilidades.\n\nComo constantemente precisamos pensar em formas diferentes de resolver os desafios que enfrentamos, acreditamos que uma base teórica sólida é mais importante que apenas ser bom em uma linguagem ou framework. Além disso queremos ver o seu melhor, e por isso não é preciso ficar limitado às tecnologias exigidas na descrição da vaga.\n\n\u003ca id=\"odesafio\"\u003e\u003c/a\u003e\n## 2. O desafio\n\nO desafio consiste em 2 problemas técnicos parecidos com os que enfrentamos na vida real.\nA resolução deles não necessariamente requer a implementação de um mega-projeto, porém ambos precisam de um certo conhecimento para serem resolvidos.\n\nLeia atentamente os enunciados dos problemas, pois apesar de não haver nenhuma pegadinha, os detalhes importam.\n\nOutros requisitos do projeto incluem:\n* Deve funcionar em um ambiente Linux;\n* Deve ter testes automatizados;\n* Deve ter um README explicando como instalar as dependências, executar as soluções e os testes.\n\n\u003ca id=\"parteum\"\u003e\u003c/a\u003e\n### Parte 1: API de usuários\n\nPrecisamos de uma API para receber a atualização de dados cadastrais de usuários. Ela deve receber um corpo no formato JSON, onde o tamanho varia desde alguns poucos kB até alguns GB.\nExperiências anteriores mostram que alguns clientes costumam enviar o mesmo corpo repetidas vezes ao longo de um curto espaço de tempo.\nIsso nos causou alguns problemas, como o fato de ter que escalar nossos bancos de dados muito além do necessário afim de aguentar a carga extra desnecessária.\nPara evitar que isto ocorra, precisamos que esta API negue requisições que tem o mesmo corpo num intervalo de 10 minutos.\n\nAqui está um exemplo do comportamento esperado:\n```bash\n# 2021-11-15T13:00:00 - primeira requisição, durante 10 minutos requests com o mesmo corpo serão negadas\ncurl -XPOST http://your-api.ozmap.com.br/v1/users -d '[{\"id\": \"123\", \"name\": \"Ada Lovelace\"}]' #=\u003e 201 CREATED\n\n# 2021-11-15T13:09:59 - mesmo corpo que a request anterior.\ncurl -XPOST http://your-api.ozmap.com.br/v1/users -d '[{\"id\": \"123\", \"name\": \"Ada Lovelace\"}]' #=\u003e 403 FORBIDDEN\n\n# 2021-11-15T13:10:00 - agora a API deve voltar a aceitar o corpo\ncurl -XPOST http://your-api.ozmap.com.br/v1/users -d '[{\"id\": \"123\", \"name\": \"Ada Lovelace\"}]' #=\u003e 201 CREATED\n```\nComo esta API atenderá milhares de requisições simultâneas, ela precisa funcionar em um cluster.\nÉ esperado que o comportamento descrito acima se mantenha, independente do nó que receber a requisição.\n\n\u003ca id=\"partedois\"\u003e\u003c/a\u003e\n### Parte 2: Agregador de URLs\n\nRecebemos um dump com lista de URLs de imagens de usuários (avatares) que vamos utilizar para manter nossa base de dados atualizada.\nEste dump contém imagens de milhões de usuários e URLs, e é atualizado a cada 10 minutos:\n\n```json\n{\"userId\": \"uid2\", \"image\": \"http://api.ozmap.com.br/test-platform/6.png\"}\n{\"userId\": \"uid1\", \"image\": \"http://api.ozmap.com.br/test-platform/1.png\"}\n{\"userId\": \"uid1\", \"image\": \"http://api.ozmap.com.br/test-platform/2.png\"}\n{\"userId\": \"uid1\", \"image\": \"http://api.ozmap.com.br/test-platform/7.png\"}\n{\"userId\": \"uid1\", \"image\": \"http://api.ozmap.com.br/test-platform/3.png\"}\n{\"userId\": \"uid1\", \"image\": \"http://api.ozmap.com.br/test-platform/1.png\"}\n{\"userId\": \"uid2\", \"image\": \"http://api.ozmap.com.br/test-platform/5.png\"}\n{\"userId\": \"uid2\", \"image\": \"http://api.ozmap.com.br/test-platform/4.png\"}\n```\n\nAs URLs pertencem a uma empresa terceirizada que hospeda a maioria destas imagens, e ela nos cobra um valor fixo por cada request.\nJá sabemos que o dump de origem não tem uma boa confiabilidade, pois encontramos várias imagens repetidas e boa parte delas também retornam status 404.\nComo não é interessante atualizar nossa base com dados ruins, filtramos apenas as URLs que retornam status 200.\n\nO processo de atualização deve receber como input um dump sanitizado, onde o formato é ligeiramente diferente da entrada:\n\n```json\n{\"userId\": \"uid1\", \"images\": [\"http://api.ozmap.com.br/test-platform/1.png\", \"http://api.ozmap.com.br/test-platform/2.png\", \"http://api.ozmap.com.br/test-platform/7.png\"]}\n{\"userId\": \"uid2\", \"images\": [\"http://api.ozmap.com.br/test-platform/3.png\", \"http://api.ozmap.com.br/test-platform/5.png\", \"http://api.ozmap.com.br/test-platform/6.png\"]}\n```\n\nPara diminuir a quantidade de requests necessárias para validar as URLs, decidimos limitar a quantidade de imagens por usuário em até 3.\nO seu objetivo é criar um programa que gera o dump final no menor tempo possível e com o mínimo de requests desnecessárias (já que existe um custo fixo por requisição).\n\nO arquivo [input-dump.tar](./resources/input-dump.tar) é um exemplo do dump de entrada. E você pode usá-lo para testar sua implementação.\nTambém criamos uma api que responde as URLs do `input-dump.tar`. Ela é apenas um mock, mas vai te ajudar a implementar a solução do desafio. Para executá-la, basta:\n\n```shell\ncd images-api\nnpm install\nnpm run start\n```\n\n\u003ca id=\"submissao\"\u003e\u003c/a\u003e\n## 3. Submissão da solução\n\nDe modo que a sua solução seja passível de ser avaliada, a mesma deverá ser submetida segundo as estipulações listadas abaixo:\n\n* Realizar o fork deste repositório;\n* Alterar a visibilidade do fork para privada;\n* Adicionar como contribuidores os seguintes usuários:\n  - [José Raupp (raupp)](https://github.com/raupp)\n* Publicar os seus commits em um branch, como o nome no formato `solution/[your-github-username]`.\n\n[**Voltar para o sumário**](#sumario)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fozmap%2Ftechnical-assessment","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fozmap%2Ftechnical-assessment","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fozmap%2Ftechnical-assessment/lists"}