# MyFreight Assessment ## How to run Easiest way to run this project is using docker compose: `docker compose up` It is possible that this will give some database connection issues on the first try, but after a couple of seconds, it should automatically reconnect. Alternatively, it is possible to use your own mysql database, and run the code locally: 1. Import the `database/entrypoint/init.sql` into your own database 2. Update the `.env` file with the database credentials 3. Run `npm ci` to install all npm packages 4. Run `npm run build` to build the nestjs application 5. Run `npm run start:prod` to start the nestjs application After starting the application will run on http://localhost:3000/ ## Documentation The full endpoint documentation can be found on http://localhost:3000/api. Here you can find which endpoints there are, and how to authenticate. ### Authentication For the Authentication I went with an base64 encoded authentication string consisting of 2 parts. The first part is the ApiKey, which is stored in the authentication database. The second part is a secret that is being used as a password. In the database we have stored 2 values, the ApiKey and a digest. This digest is creating by using HMAC with the api secret as password, using a sha256 to hash the ApiKey. This way there is no full api key stored in the database. #### Demo example In this demo you can use `eG5nVnZGaWtCMFN6NjRRaWQ2TUJsUTJWaDpjeGg1R3FKRUl0UTlzSGRQdElGMGg0bFJp` for the requests. This decodes to `xngVvFikB0Sz64Qid6MBlQ2Vh:cxh5GqJEItQ9sHdPtIF0h4lRi`. The first part `xngVvFikB0Sz64Qid6MBlQ2Vh` is stored in the database, but the second part is not stored anywhere. ## Receiving Tracking information When receiving Tracking information, the following steps need to be completed to process the data ```mermaid flowchart TD receiveTracking(["Receive Tracking"]) findContainerAndShipment["SELECT container JOIN Shipment"] updateShipment[/Update shipment\] isArrivingSoon{{"Is arrival estimate between now and now + 24h?"}} hasArrived{{"Is arrival estimate <=now?"}} isDelayed{{Is arrival estimate > original arrival + 24h?}} sendNotification[/Send notification\] receiveTracking -- "`**Tracking data** carrierName:**string** destinationUnLoCode:**string** departureDate:**string[_datetime_]** arrivalDateEstimate:**string[_datetime_]** containerNumber:**string** `" --> findContainerAndShipment findContainerAndShipment --> |WHERE containers.containerNumber = :trackingData.containerNumber| updateShipment updateShipment --> isArrivingSoon & hasArrived & isDelayed isDelayed -->|set delayed flag| sendNotification hasArrived --> |set has arrived flag| sendNotification isArrivingSoon -->|set is arriving soon flag| sendNotification %% isArrivingSoon -->|yes| sendArriveSoon ``` ## Possible improvements - Sending the actual notification, there should be a more general way to setup notifiers - Moving some variables to config files - when is a shipment "arriving soon" - mock date - Use the uuid package - was not possible since the uuid's from the sample data were invalid uuid's - Add end-to-end tests as well - Get shipments should be paginated - Could use a package like typeorm-crud - Cleanup duplicate OpenApi decorators, perhaps consolidate them in a custom decorator