{"id":23011509,"url":"https://github.com/neulabscom/backend-assignment","last_synced_at":"2026-01-15T22:38:06.741Z","repository":{"id":251932850,"uuid":"650558878","full_name":"neulabscom/backend-assignment","owner":"neulabscom","description":null,"archived":false,"fork":false,"pushed_at":"2024-08-06T14:40:27.000Z","size":12,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-02-08T07:28:16.905Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"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/neulabscom.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}},"created_at":"2023-06-07T10:21:35.000Z","updated_at":"2024-08-06T14:40:31.000Z","dependencies_parsed_at":"2024-08-06T17:02:15.558Z","dependency_job_id":"1ef04756-f1e4-4551-a8c8-15d4db682fc1","html_url":"https://github.com/neulabscom/backend-assignment","commit_stats":null,"previous_names":["neulabscom/backend-assignment"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neulabscom%2Fbackend-assignment","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neulabscom%2Fbackend-assignment/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neulabscom%2Fbackend-assignment/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neulabscom%2Fbackend-assignment/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neulabscom","download_url":"https://codeload.github.com/neulabscom/backend-assignment/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246856675,"owners_count":20844974,"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":[],"created_at":"2024-12-15T10:09:21.552Z","updated_at":"2026-01-15T22:38:06.713Z","avatar_url":"https://github.com/neulabscom.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Neulabs Backend Assessment\n\n## Requirements\n\nDocker must be installed in the machine to be able to run the compose file.\n\n## Constraints\n\nFeel free to add any services to the compose if you feel like doing it or use\nany framework you want!\nThe only constraint for this test is that solution of the assessment must be written in TypeScript.\n\n## Setup\nFrom the root folder of the project\n```\ndocker-compose up -d\nnpm run migrate\n```\n\n## Implementation Context\n\nThis assessment is a real (but simplified) operational flow that we have already implemented.\n\nThe purpose of this flow is to process realtime incoming `order` events purchased by customers.  \nFor each order that enters the system, it must understand if the `order` is shippable and, when it is, with  \nwhich `courier`.\n\nAny of the architectural and project structure choices are up to you.\n\n## Assessment\n\nGiven the input structured as the example bellow, develop a solution that will elaborate the `order` with the  \nfollowing specs:\n1. if the `order` contains _more than 3_ unique items (ignore the quantity of each item) the order must be split in  \n   `n` sub-orders (called `fulfillments` from now on. Look at the example to see how a `fulfillment` is structured).\n2. each generated fulfillment must contain a detail of all the products adding the `weight` and `price` that can be found on the database. (assume that the `weight` is in grams and the `price` is in euro)\n\n    You need to update the quantity of each product in the database when making these fulfillments.\n3. for each generated `fulfillment` we need to select the courier by applying the following rules:\n  - if there are 1 or 2 unique items, still excluding the `quantity`, in the `fulfillment` \n    then we pick a random courier from the available courier in the database\n  - if it contains 3 items then we take the sum of the `weight` (this time we take `quantity` into account) of all the products,  \n    and we select the courier with the lower cost (based on the `courier_price_range` table) using the total  \n    calculated `weight`\n\n## Extra:\n1. store the orders and the fulfilments\n2. handle the case if a product is not shippable with any courier, store the order \nwith an error state (for example the weight is too high and there's no way to ship \nit or there's no more quantities in the database)\n\n\n## Additional Notes\n\n- The user must not be saved for privacy issue. \n- The ranges of the weight table must be considered start inclusive and end exlcusive, so: [start, end)\n\n\n## Example\n\nGiven the following input:\n\n```json  \n{  \n    \"id\": \"OrderId1\",  \n    \"customer\": {  \n        \"id\": \"1\",  \n        \"email\": \"nick@gmail.com\",  \n        \"firstName\": \"Nome\",  \n        \"addresses\": [  \n            {  \n                \"city\": \"City\",  \n                \"apartmentNumber\": 27,  \n                \"street\": \"Via Di casa\",  \n                \"fullName\": \"Nome Cognome\"  \n            }  \n        ],  \n        \"phoneNumber\": \"+39 333 008 3333\",  \n        \"lastName\": \"Cognome\"  \n    },  \n    \"addressInfo\": {  \n        \"city\": \"City\",  \n        \"name\": \"Nome Cognome\",  \n        \"apartmentNumber\": 27,  \n        \"street\": \"Via Di casa\",  \n        \"fullName\": \"Nome Cognome\"  \n    },  \n    \"lineItems\": [  \n        {  \n            \"id\": \"id1\",  \n            \"name\": \"Prod1\",  \n            \"qta\": 5  \n        },  \n        {  \n            \"id\": \"id2\",  \n            \"name\": \"Prod2\",  \n            \"qta\": 1  \n        },  \n        {  \n            \"id\": \"id3\",  \n            \"name\": \"Prod3\",  \n            \"qta\": 3  \n        },  \n        {  \n            \"id\": \"id4\",  \n            \"name\": \"Prod4\",  \n            \"qta\": 3  \n        }  \n    ]  \n}  \n```  \n\nThe expected output is the generation of 2 `fulfillments` like the following:\n\n```json  \n{\n  \"id\": \"1\",\n  \"orderId\": \"OrderId1\",\n  \"customer\": {\n    \"id\": \"1\",\n    \"email\": \"nick@gmail.com\",\n    \"firstName\": \"Nome\",\n    \"addresses\": [\n      {\n        \"city\": \"City1\",\n        \"apartmentNumber\": 27,\n        \"street\": \"Via Di casa\",\n        \"fullName\": \"Nome Cognome\"\n      }\n    ],\n    \"phoneNumber\": \"+39 333 008 3333\",\n    \"lastName\": \"Cognome\"\n  },\n  \"shippingAddress\": {\n    \"city\": \"City1\",\n    \"apartmentNumber\": 27,\n    \"street\": \"Via Di casa\",\n    \"fullName\": \"Nome Cognome\"\n  },\n  \"products\": [\n    {\n      \"id\": \"id1\",\n      \"name\": \"Prod1\",\n      \"qta\": 5,\n      \"weight\": 10,\n      \"price\": 10\n    },\n    {\n      \"id\": \"id2\",\n      \"name\": \"Prod2\",\n      \"qta\": 1,\n      \"weight\": 11,\n      \"price\": 20\n    },\n    {\n      \"id\": \"id3\",\n      \"name\": \"Prod3\",\n      \"qta\": 3,\n      \"weight\": 12,\n      \"price\": 30\n    }\n  ],\n  \"courier\": \"PDB\"\n}  \n```  \n\n```json  \n{  \n    \"id\": \"1\",  \n    \"orderId\": \"OrderId1\",  \n    \"customer\": {  \n        \"id\": \"1\",  \n        \"email\": \"nick@gmail.com\",  \n        \"firstName\": \"Nome\",  \n        \"addresses\": [  \n            {  \n                \"city\": \"City1\",  \n                \"apartmentNumber\": 27,  \n                \"street\": \"Via Di casa\",  \n                \"fullName\": \"Nome Cognome\"  \n            }  \n        ],  \n        \"phoneNumber\": \"+39 333 008 3333\",  \n        \"lastName\": \"Cognome\"  \n    },  \n    \"shippingAddress\": {  \n        \"city\": \"City\",  \n        \"apartmentNumber\": 27,  \n        \"street\": \"Via Di casa\",  \n        \"fullName\": \"Nome Cognome\"  \n    },  \n    \"products\": [  \n        {  \n        \"id\": \"id4\",  \n        \"name\": \"Prod4\",  \n        \"qta\": 3,  \n        \"weight\": 15,  \n        \"price\": 21  \n        }  \n    ],  \n    \"courier\": \"BRT\"  \n}  \n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneulabscom%2Fbackend-assignment","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneulabscom%2Fbackend-assignment","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneulabscom%2Fbackend-assignment/lists"}